
识别 POCO Controller言归正题因为 POCO Controllers 不从 Microsoft.AspNet.Mvc.Controller 基类派生ASP.NET vNext 如何识别 POCO Controller关于这个问题在 stackoverflow 中提问“How Are POCO Controllers Discovered As Controllers?”回答如下There are some conventions that we use to identify a POCO controller:The assembly must reference MVC必须引用 MVCThe POCO controller class must have the suffix ControllerPOCO controller 必须以“Controller”后缀结尾必须引用 MVC 就是在 project.json 中添加如下如下引用2简单 POCO Controller最简单的 POCO Controller1 // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID397860 2 3 namespace PocoControllerDemo.Controllers 4 { 5 public class HelloWorldController 6 { 7 // GET: /controller/ 8 public string Index() 9 { 10 return Hello World; 11 } 12 } 13 }注意 HelloWorldController 并没有继承 Controller这种写法在 ASP.NET vNext 是可以的因为未涉及到 Controller 的核心操作如View、Url、Action等只是返回一个字符串内置依赖注入映射默认配置首先我们看下 DefaultControllerFactory 中的源码1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 2 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 3 4 using System; 5 using Microsoft.AspNet.Mvc.Core; 6 using Microsoft.AspNet.Mvc.ModelBinding; 7 using Microsoft.Framework.DependencyInjection; 8 9 namespace Microsoft.AspNet.Mvc 10 { 11 public class DefaultControllerFactory : IControllerFactory 12 { 13 private readonly ITypeActivator _activator; 14 private readonly IServiceProvider _serviceProvider; 15 16 public DefaultControllerFactory(IServiceProvider serviceProvider, ITypeActivator activator) 17 { 18 _serviceProvider serviceProvider; 19 _activator activator; 20 } 21 22 public object CreateController(ActionContext actionContext) 23 { 24 var actionDescriptor actionContext.ActionDescriptor as ReflectedActionDescriptor; 25 if (actionDescriptor null) 26 { 27 throw new ArgumentException( 28 Resources.FormatDefaultControllerFactory_ActionDescriptorMustBeReflected( 29 typeof(ReflectedActionDescriptor)), 30 actionContext); 31 } 32 33 var controller _activator.CreateInstance( 34 _serviceProvider, 35 actionDescriptor.ControllerDescriptor.ControllerTypeInfo.AsType()); 36 37 InitializeController(controller, actionContext); 38 39 return controller; 40 } 41 42 public void ReleaseController(object controller) 43 { 44 var disposableController controller as IDisposable; 45 46 if (disposableController ! null) 47 { 48 disposableController.Dispose(); 49 } 50 } 51 52 private void InitializeController(object controller, ActionContext actionContext) 53 { 54 Injector.InjectProperty(controller, ActionContext, actionContext); 55 56 var viewData new ViewDataDictionary( 57 _serviceProvider.GetServiceIModelMetadataProvider(), 58 actionContext.ModelState); 59 Injector.InjectProperty(controller, ViewData, viewData); 60 61 var urlHelper _serviceProvider.GetServiceIUrlHelper(); 62 Injector.InjectProperty(controller, Url, urlHelper); 63 64 Injector.CallInitializer(controller, _serviceProvider); 65 } 66 } 67 }3IActionResultHelperInitializeController 方法用来初始化控制器可以看出如果我们没有添加任何的配置操作ASP.NET vNext 会通过内置的 IoC 容器注入默认的类型映射比如上面的 HelloWorldController。主要包含三个类型ActionContext、ViewDataDictionary 和 IUrlHelper从单词上可以简单看出这三种类型所包含的意义ViewDataDictionary 视图操作的数据字典这个在控制器返回 View 的时候会用到这个后面有说明我们看下在 MSDN 中关于 POCO Controller 的简单示例项目地址ASP.NET Core, an open-source web development framework | .NET示例代码1 public class HomeController 2 { 3 // Helpers can be dependency injected into the controller 4 public HomeController(IActionResultHelper resultHelper) 5 { 6 Result resultHelper; 7 } 8 9 private IActionResultHelper Result { get; set; } 10 11 public ActionResult Index() 12 { 13 return Result.Json(new { message Poco controllers! }); 14 } 15 }执行结果代码中主要对 IActionResultHelper 进行构造函数注入你可以实现属于自己的 IActionResultHelper 实例使用 ASP.NET vNext 内置IoC容器进行依赖注入IActionResultHelper 是什么IActionResultHelper is a helper for creating action results。就是说 IActionResultHelper 用来创建 Action 结果的契约Index 方法中返回一个 Json 格式数据返回类型为ActionResultResult.Json 也就是 IActionResultHelper.Json也就是说所有的一切都表明你可以创建属于自己的 IActionResultHelper包含自定义的 IActionResultHelper.Json 类型格式。以下是在 MSDN 中找到仅存的关于 POCO Controller 的说明The Controller class also gives you convenient access to the HTTP request context, the current principal (IPrincipal), a view bag, and other useful properties. So the Controller class is certainly useful, but it’s not required. For a light-weight controller, you might prefer a POCO controller.4IModelMetadataProvider、ViewDataDictionary以上是有关 Action 的操作如果涉及到 View 操作又是怎么实现MSDN 太坑爹了都没有详细说明有位国外哥们和我遇到一样的问题了详细地址http://geekswithblogs.net/stun/archive/2014/06/04/asp.net-vnext-blog-post-series.aspx以下来自这位国外哥们的描述Today, I want to start this blog post series with a teaser code snippet for those developers familiar with the ASP.NET MVC.Getting Started with ASP.NET MVC 6 article from ASP.NET website shows how to write a lightweight POCO (plain-old CLR object) MVC Controller class in the upcoming ASP.NET MVC 6.However, it doesnt show us how to use the IActionResultHelper interface to render a View.This is how I wrote my POCO MVC Controller based on the https://github.com/aspnet/Home/blob/master/samples/HelloMvc/Controllers/HomeController.cs sample from Github.虽然在 MSDN 中关于 View 操作没有相关说明但是这位国外哥们搞出来了不服不行啊所谓前人种树后人乘凉来看一下这位哥们的解决方案1 using Microsoft.AspNet.Mvc; 2 using Microsoft.AspNet.Mvc.ModelBinding; 3 using MvcSample.Web.Models; 4 5 namespace MvcSample.Web 6 { 7 public class HomeController 8 { 9 IActionResultHelper html; 10 IModelMetadataProvider mmp; 11 12 public HomeController(IActionResultHelper h, IModelMetadataProvider mmp) 13 { 14 this.html h; 15 this.mmp mmp; 16 } 17 18 public IActionResult Index() 19 { 20 var viewData new ViewDataDictionaryUser(mmp) { Model User() }; 21 return html.View(Index, viewData); 22 } 23 24 public User User() 25 { 26 return new User { Name My name, Address My address }; 27 } 28 } 29 }可以看出除了 IActionResultHelper 类型映射还包含 IModelMetadataProvider 类型关于 IModelMetadataProvider 可以从 DefaultControllerFactory 源码中得到一些信息在创建 ViewDataDictionary 实例的时候需要传入 IModelMetadataProvider 类型的参数也就是代码中的 new ViewDataDictionaryUser(mmp) { Model User() }; IModelMetadataProvider 需要引入 using Microsoft.AspNet.Mvc.ModelBinding关于 IModelMetadataProvider 定义请参照1 using System; 2 using System.Collections.Generic; 3 4 namespace Microsoft.AspNet.Mvc.ModelBinding 5 { 6 public interface IModelMetadataProvider 7 { 8 IEnumerableModelMetadata GetMetadataForProperties(object container, Type containerType); 9 ModelMetadata GetMetadataForProperty(Funcobject modelAccessor, Type containerType, string propertyName); 10 ModelMetadata GetMetadataForType(Funcobject modelAccessor, Type modelType); 11 } 12 }html.View(Index, viewData); 使用方式就像我们平常向 View 传入数据一样如果不传入数据但是也要传入 ViewDataDictionary 类型参数修改 HelloWorldController 控制器代码1 using Microsoft.AspNet.Mvc; 2 using Microsoft.AspNet.Mvc.ModelBinding; 3 4 // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID397860 5 6 namespace PocoControllerDemo.Controllers 7 { 8 public class HelloWorldController 9 { 10 private IActionResultHelper actionResultHelper { get; set; } 11 private IModelMetadataProvider modelMetadataProvider { get; set; } 12 // Helpers can be dependency injected into the controller 13 public HelloWorldController(IActionResultHelper resultHelper, IModelMetadataProvider metadataProvider) 14 { 15 actionResultHelper resultHelper; 16 modelMetadataProvider metadataProvider; 17 } 18 // GET: /controller/ 19 public ActionResult Index() 20 { 21 //return Result.Json(new { message Poco controllers! }); 22 var viewData new ViewDataDictionary(modelMetadataProvider);