IoC在ASP.NET Web API中的应用
控制反转(Inversion of Control,IoC),简单地说,就是应用本身不负责依赖对象的创建和维护,而交给一个外部容器来负责。这样控制权就由应用转移到了外部IoC容器,控制权就实现了所谓的反转。比如在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。通过IoC的方式实现针对目标HttpController的激活具有重要的意义。[本文已经同步到《How ASP.NET Web API Works?》]
一、 基于IoC的HttpControllerActivator
将IoC应用于HttpController激活系统的目的在于让一个预定义的IoC容器来提供最终的HttpController对象。通过《ASP.NET Web API的Controller是如何被创建的?》的介绍我们知道HttpController的激活最终由HttpControllerActivator对象来完成,所以将IoC与ASP.NET Web API的HttpController激活系统进行集成最为直接的方式莫过于自定义一个HttpControllerActivator。
我们通过一个简单实例来演示如何通过自定义HttpControllerActivator的方式实现与IoC的集成,我们采用的IoC框架是Unity。我们在一个ASP.NET Web API应用中定义了这个UnityHttpControllerActivator类型。UnityHttpControllerActivator具有一个表示Unity容器的属性UnityContainer,该属性在构造函数中被初始化。在用于创建的HttpController的Create方法中,我们调用此UnityContainer对象的Resolve方法创建目标HttpController对象。
- 1: public class UnityHttpControllerActivator : IHttpControllerActivator
- 2: {
- 3: public IUnityContainer UnityContainer { get; private set; }
- 4:
- 5: public UnityHttpControllerActivator(IUnityContainer unityContainer)
- 6: {
- 7: this.UnityContainer = unityContainer;
- 8: }
- 9:
- 10: public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
- 11: {
- 12: return (IHttpController)this.UnityContainer.Resolve(controllerType);
- 13: }
- 14: }
接下来我们定义了如下一个继承自ApiController的ContactsController来管理联系人信息。简单起见,我们只定义了唯一的Action方法Get用于获取联系人信息。该方法具有一个可缺省的参数id表示希望获取的联系人的ID,如果没有提供此参数则返回所有联系人列表。
- 1: public class ContactsController : ApiController
- 2: {
- 3: public IContactRepository Repository { get; private set; }
- 4: public ContactsController(IContactRepository repository)
- 5: {
- 6: this.Repository = repository;
- 7: }
- 8: public IEnumerable<Contact> Get(string id = "")
- 9: {
- 10: return this.Repository.GetContacts(contact =>
- 11: string.IsNullOrEmpty(id) || id == contact.Id);
- 12: }
- 13: }
- 14:
- 15: public class Contact
- 16: {
- 17: public string Id { get; set; }
- 18: public string Name { get; set; }
- 19: public string PhoneNo { get; set; }
- 20: public string EmailAddress { get; set; }
- 21: public string Address { get; set; }
- 22: }
Action方法利用Repository属性返回的对象来实施联系人的查询工作,这个IContactRepository接口类型的属性在构造函数中初始化。我们利用IContactRepository接口来抽象对联系人数据的存储,如下面的代码片断所示,我们在此接口中仅定义了唯一的GetContacts方法根据指定的添加来筛选对应的联系人列表。
- 1: public interface IContactRepository
- 2: {
- 3: IEnumerable<Contact> GetContacts(Predicate<Contact> predicate);
- 4: }
我们定义了如下一个DefaultContactRepository类型作为IContactRepository接口的默认实现者,简单起见,我们采用一个静态字典来保存联系人列表。
- 1: public class DefaultContactRepository : IContactRepository
- 2: {
- 3: private static List<Contact> contacts = new List<Contact>
- 4: {
- 5: new Contact{ Id="001", Name = "张三", PhoneNo="123", EmailAddress = "zhangsan@gmail.com"},
- 6: new Contact{ Id="002", Name = "李四", PhoneNo="456",EmailAddress = "lisi@gmail.com"}
- 7: };
- 8:
- 9: public IEnumerable<Contact> GetContacts(Predicate<Contact> predicate)
- 10: {
- 11: return contacts.Where(contact=>predicate(contact));
- 12: }
- 13: }
我们在Global.asax中对自定义的UnityHttpControllerActivator进行了注册。如下面的代码片断所示,我们在Application_Start方法中创建了一个UnityContainer对象,并通过调用泛型方法RegisterType<TFrom,TTo>注册了IContactRepository接口和DefaultContactRepository类型之间的匹配关系。我们最后根据这个UnityContainer创建一个UnityHttpControllerActivator对象,并将其注册到当前ServicesContainer上。
- 1: public class WebApiApplication: System.Web.HttpApplication
- 2: {
- 3: protected void Application_Start()
- 4: {
- 5: //其他操作
- 6: IUnityContainer unityContainer = new UnityContainer();
- 7: unityContainer.RegisterType<IContactRepository, DefaultContactRepository>();
- 8: GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new UnityHttpControllerActivator(unityContainer));
- 9: }
- 10: }
当此ASP.NET Web API应用运行之后,我们可以直接在浏览器中输入相应的地址获取所有联系人列表(“/api/contacts”)和针对某个ID为“001”(“/api/contacts/001”)的联系人信息,相应的联系人信息会以如下图所示的形式出现在浏览器上。

二、基于IoC的DependencyResolver
由于默认的DefaultHttpControllerActivator会先利用当前注册的DependencyResolver对象去激活目标HttpController,所以除了利用自定义的HttpControllerActivator将IoC引入HttpController激活系统之外,另一个有效的方案就是注册自定义的DependencyResolver。
接下来将要自定义的DependencyResolver基于另一个叫作“Ninject”的IoC框架。较之Unity,Ninject是一个更加轻量级的IoC框架。篇幅所限,我们不便对这个IoC框架作过多的介绍,有兴趣的读者可以访问其官网(“http://www.ninject.org/”)了解Ninject。
- 1: public class NinjectDependencyResolver : IDependencyResolver
- 2: {
- 3: private List<IDisposable> disposableServices = new List<IDisposable>();
- 4: public IKernel Kernel { get; private set; }
- 5:
- 6: public NinjectDependencyResolver(NinjectDependencyResolver parent)
- 7: {
- 8: this.Kernel = parent.Kernel;
- 9: }
- 10:
- 11: public NinjectDependencyResolver()
- 12: {
- 13: this.Kernel = new StandardKernel();
- 14: }
- 15:
- 16: public void Register<TFrom, TTo>() where TTo : TFrom
- 17: {
- 18: this.Kernel.Bind<TFrom>().To<TTo>();
- 19: }
- 20:
- 21: public IDependencyScope BeginScope()
- 22: {
- 23: return new NinjectDependencyResolver(this);
- 24: }
- 25:
- 26: public object GetService(Type serviceType)
- 27: {
- 28: return this.Kernel.TryGet(serviceType);
- 29: }
- 30:
- 31: public IEnumerable<object> GetServices(Type serviceType)
- 32: {
- 33: foreach (var service in this.Kernel.GetAll(serviceType))
- 34: {
- 35: this.AddDisposableService(service);
- 36: yield return service;
- 37: }
- 38: }
- 39:
- 40: public void Dispose()
- 41: {
- 42: foreach (IDisposable disposable in disposableServices)
- 43: {
- 44: disposable.Dispose();
- 45: }
- 46: }
- 47:
- 48: private void AddDisposableService(object servie)
- 49: {
- 50: IDisposable disposable = servie as IDisposable;
- 51: if (null != disposable && !disposableServices.Contains(disposable))
- 52: {
- 53: disposableServices.Add(disposable);
- 54: }
- 55: }
- 56: }
我们创建了如上一个类型为NinjectDependencyResolver的自定义DependencyResolver。NinjectDependencyResolver的核心是类型为IKernel的只读属性Kernel,用于获取服务实例的GetService和GetServices方法分别通过调用此Kernel属性的TryGet和GetAll方法来实现。BeginScope方法返回一个新的NinjectDependencyResolver对象,它与自身拥有同一个Kernel对象。我们定义了额外的方法Register<TFrom,TTo>来注册接口与实现类型之间的映射关系。为了确保获取的服务实例能够被正常地释放,我们定义了一个元素类型为IDisposable的列表。如果获取的对象实现了IDisposable接口,它会被放入这个列表中,我们在实现的Dispose方法中释放该列表中的所有对象。
现在我们将这个自定义的NinjectDependencyResolver应用到上一个演示实例中。我们只需要将Global.asax中针对自定义HttpControllerActivator的注册替换成针对NinjectDependencyResolver的注册即可。运行此ASP.NET Web API应用后通过浏览器试图获取联系人信息,我们依然会得到如上图所示的结果。
- 1: public class MvcApplication : System.Web.HttpApplication
- 2: {
- 3: protected void Application_Start()
- 4: {
- 5: //其他操作
- 6: NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver();
- 7: dependencyResolver.Register<IContactRepository, DefaultContactRepository>();
- 8: GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;
- 9: }
- 10: }
IoC在ASP.NET Web API中的应用的更多相关文章
- 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建
目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...
- ASP.NET Web API 中的返回数据格式以及依赖注入
本篇涉及ASP.NET Web API中的返回数据合适和依赖注入. 获取数据 public IEnumerable<Food> Get() { var results = reop.Get ...
- ASP.NET Web API中的Controller
虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...
- 在ASP.NET Web API中使用OData
http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...
- ASP.NET Web API 中的异常处理(转载)
转载地址:ASP.NET Web API 中的异常处理
- 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化
谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...
- Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...
- ASP.NET WEB API 中的路由调试与执行过程跟踪
路由调试 RouteDebugger 是调试 ASP.NET MVC 路由的一个好的工具,在ASP.NET WEB API中相应的有 WebApiRouteDebugger ,Nuget安装 Inst ...
- 能省则省:在ASP.NET Web API中通过HTTP Headers返回数据
对于一些返回数据非常简单的 Web API,比如我们今天遇到的“返回指定用户的未读站内短消息数”,返回数据就是一个数字,如果通过 http response body 返回数据,显得有些奢侈.何不直接 ...
随机推荐
- Centos 6.5 x64环境下 spark 1.6 maven 编译-- 已验证
Centos 6.5 x64 jdk 1.7 scala 2.10 maven 3.3.3 cd spark-1.6 export MAVEN_OPTS="-Xmx2g -XX:MaxPer ...
- Tomat简介
Tomcat目录结构bin: 存放各种平台下启动和关闭Tomcat的脚本文件.startup.bat是windows下启动tomcat的文件,shutdown.bat是关闭tomcat的文件.comm ...
- 限制input只能输入金额(类似:100.00|100.9|100)
$(".inputmoney").keyup(function () { var reg = $(this).val().match(/\d+\.?\d{0,2}/); ...
- js中获取css的样式
因为给定一个div宽度或者其他样式之后,再设置一个border的宽度在js中得到的obj.setoffWidth就会变成width加上border的二倍宽度,因此可以自己写一个方法来获取样式.(obj ...
- ECF R9(632E) & FFT
Description: 上一篇blog. Solution: 同样我们可以用fft来做...就像上次写的那道3-idoit一样,对a做k次卷积就好了. 同样有许多需要注意的地方:我们只是判断可行性, ...
- 导入数据经常使用的SQL语句整理整理
1.事务(基本) GO BEGIN TRY BEGIN TRAN -- 导入数据 COMMIT TRAN END TRY BEGIN CATCH ROLLBACK TRAN END CATCH GO ...
- 数据泵Expdp和Impdp
一.数据泵导入导出技术 1.结构 2.目录对象 二.EXPDP参数 1.attach 2.content 3.directory 4.dumpfile 5.estimate 6.estimate_on ...
- android 开发 gradle 自己会容易混淆的东西
使用intellij idea 开发android ,关于 gradle 和 android gradle plugin 容易混淆地方,做下记录: 一. build.gradle 文件有两个地方存在, ...
- Master-Slave通用基础框架
一.设计目的 设计出一个通用的Master-Slave基础框架,然后可以基于这个框架来实现特定的业务需求,比如实现多节点并行计算.分布式处理等. 二.设计理念 基于经典的命令模式,Master和Sla ...
- 网络问卷调查js实现代码
昨天一个同行妹纸写了一个网络问卷调查的效果,但是有bug,于是就来问我该如何解决这个bug.经过我的分析,bug主要还是出在复选框的那部分,经过修改,bug问题解决,现在贴出如下代码,仅供大家参考: ...