ASP.NET MVC 控制器激活(二)
前言
在之前的篇幅中。用文字和图像来表示了控制器的激活过程,描写叙述的角度都是从框架默认实现的角度去进行描写叙述的。这样也使得大家都能够清楚的知道激活的过程以及当中涉及到的对象模型,今天的篇幅就是在激活的过程中。框架提供了哪些可注入点。站在一个使用者的角度来进行描写叙述。
激活控制器-注入点入口
如上图。这是上个篇幅中描写叙述的控制器激活过程图。这里引用过来是怕有的朋友忘记了前面的所说和没看过前面篇幅的朋友。
就从默认控制器工厂的实现来看,在CreateController()方法中。通过GetControllerType()方法来获取控制器类型(Type),然后传递到GetControllerInstance()方法中,通过当中的实现来完毕依据控制器类型(Type)到IController的生成。而在兴许的注入点也是在GetControllerInstance()方法实现中来进行注入的,GetControllerInstance()方法即是整个控制器激活过程的入口点。
IoC演示样例
既然说到了动态注入,想必就要用到IoC框架了,在MVC学前篇中提到过Ninject的使用。以下这个演示样例便是依赖于Ninject的来做的演示:
1 /// <summary> 2 /// 产品实体类 3 /// </summary> 4 public class Product 5 { 6 public string ID { get; set; } 7 public string Name { get; set; } 8 }
定义一个数据实体类没什么好说的,
1 /// <summary> 2 /// 抽象数据提取库 3 /// </summary> 4 public interface IDataStandard 5 { 6 List<Product> GetProducts(); 7 } 8 /// <summary> 9 /// 默认实现--数据提取库 10 /// </summary> 11 public class DataProvide : IDataStandard 12 { 13 14 public List<Product> GetProducts() 15 { 16 List<Product> products = new List<Product>() 17 { 18 new Product(){ ID="1",Name="name1"}, 19 new Product(){ID="2",Name="name2"}, 20 new Product(){ID="3",Name="name3"} 21 }; 22 return products; 23 } 24 }
这里定义的一个是抽象的数据提取库,和一个默认的实现作为演示用于提供数据用的。
1 /// <summary> 2 /// 抽象数据调用 3 /// </summary> 4 public interface IDataCall 5 { 6 void WriterToMonitor(); 7 } 8 9 /// <summary> 10 /// 默认的数据调用实现 11 /// </summary> 12 public class DefultDataCall:IDataCall 13 { 14 private IDataStandard _DataStandard; 15 16 public DefultDataCall(IDataStandard dataStandard)//使用构造函数方式注入 通过Ninject框架实现 17 { 18 _DataStandard = dataStandard; 19 } 20 21 public void WriterToMonitor() 22 { 23 foreach(var data in _DataStandard.GetProducts()) 24 { 25 Console.WriteLine("Prodcut ID:" + data.ID + " Name:" + data.Name); 26 } 27 } 28 }
这里定义的是抽象的数据调用和默认的实现,我们如今要做的就是通过IoC框架来让调用client对数据调用和数据提取解耦,
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 IKernel ninject = new StandardKernel(); 6 ninject.Bind<IDataStandard>().To<DataProvide>(); 7 IDataCall dataCall = ninject.Get(typeof(DefultDataCall)) as IDataCall; 8 if (dataCall != null) 9 { 10 dataCall.WriterToMonitor(); 11 } 12 13 Console.ReadLine(); 14 } 15 }
执行这段代码:
非常easy明了的一个演示样例。在MVC的项目中也是这样执行的。
MVC项目中的运用
在上面的章节里说过,入口点在protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType);方法中,我们仅仅须要实现一个默认的控制器工厂类型。而且重写一下这种方法。由于我们已经能够在重写的方法中获取到控制器的类型了。有了它就能够依照IoC演示样例中的那样来进行其他对象到控制器的一个动态注入。
我们先要定义一个控制器。而且要让它对上述演示样例中的抽象提取库依赖。採取构造函数式注入(依赖)。
看一下演示样例:
1 public class IoCDemoController : Controller 2 { 3 // 4 // GET: /IoCDemo/ 5 6 private IDataStandard _DataStandard; 7 8 public IoCDemoController(IDataStandard dataStandard) 9 { 10 _DataStandard = dataStandard; 11 } 12 13 public ActionResult Index() 14 { 15 return View(_DataStandard.GetProducts()); 16 } 17 }
在Index方法上右键,点击加入视图:
点击加入,而且在视图中输入例如以下代码:
@model IEnumerable<ConsoleApplication2.Product> @{ ViewBag.Title = "Index"; } <h2>Index</h2> @foreach (var item in Model) { <h3>ID: @item.ID Name:@item.Name</h3> }
再把Global.asax文件里的路由设置改动一下:
1 routes.MapRoute( 2 "Default", // 路由名称 3 "{controller}/{action}/{id}", // 带有參数的 URL 4 new { controller = "IoCDemo", action = "Index", id = UrlParameter.Optional } // 參数默认值 5 );
这个时候准备工作都做好。但是控制器中所用的数据哪里来呢?从我们默认实现的控制器工厂中来:
1 public class NinjectControllerFactory :DefaultControllerFactory 2 { 3 private IKernel _NinjectKernel; 4 5 public NinjectControllerFactory() 6 { 7 _NinjectKernel = new StandardKernel(); 8 _NinjectKernel.Bind<IDataStandard>().To<DataProvide>(); 9 } 10 11 protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 12 { 13 IController controller = _NinjectKernel.Get(controllerType) as IController; 14 if (controller != null) 15 { 16 return controller; 17 } 18 return null; 19 } 20 21 }
依照上面章节中的样式,在NinjectControllerFactory中事先绑定数据类型。等到系统执行须要用到控制器的时候会通过Ninject框架来讲数据动态的注入到控制器中。
最后还要设置一项:
在Global.asax文件里的Application_Start()方法中要把我们默认的实现的控制器工厂设置到MVC框架中。
1 protected void Application_Start() 2 { 3 AreaRegistration.RegisterAllAreas(); 4 5 RegisterGlobalFilters(GlobalFilters.Filters); 6 RegisterRoutes(RouteTable.Routes); 7 ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); 8 }
加入上代码的最后一句。如今我们就能够来看一下终于效果了。
本篇就说到这里,会在下个篇幅中继续解说其他的注入点。