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: }

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-10-28 20:03:50

IoC在ASP.NET Web API中的应用的相关文章

在ASP.NET Web API中使用OData

一.什么是ODataOData是一个开放的数据协议(Open Data Protocol) 在ASP.NET Web API中, 对于CRUD(create, read, update, and delete)应用比传统WebAPI增加了很大的灵活性 只要正确使用相关的协议,可以在同等情况下 对一个CRUD应用可以节约很多开发时间,从而提高开发效率 二.怎么搭建 做一个简单的订单查询示例 我们使用Code First模式创建两个实体对象Product(产品),Supplier(供应商) 1.新建

Asp.Net Web API 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 Web API中的JSON和XML格式化器. 在ASP.NET Web API中,媒体类型格式化器(Media-type Formatter)是一种能够做以下工作的对象: 从HTTP消息体读取

【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

原文:[ASP.NET Web API教程]6.2 ASP.NET Web API中的JSON和XML序列化 谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予"推荐".但前几天有人询问为何很久没有更新,这让我感觉把这文章翻译出来还是有价值的.为此,本人打算将此工作继续下去.这些关于Web API的技术文章均由微软专业人员撰写,虽然文章作为博客帖子而写得比较简单

【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理

原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内容. Exception Handling in ASP.NET Web API ASP.NET Web API中的异常处理 本文引自:http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling

ASP.NET Web API中的Controller

虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要求它实现IHttpController接口即可,所以我们将其统称为HttpController.既然HttpController指的是所有实现了IHttpController接口的类型,我们自然得先来了解一下这个接口的定义.如下面的代码片断所示,在IHttpController接口中仅仅定义了唯一的

【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie

原文:[ASP.NET Web API教程]5.5 ASP.NET Web API中的HTTP Cookie 5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.NET Web API中的HTTP Cookie 本文引自:http://www.asp.net/web-api/overview/working-with-http/http-cookies By Mike Wasson|September 17, 2012 作者:Mike Wasson | 日期:

【ASP.NET Web API教程】4.1 ASP.NET Web API中的路由

原文:[ASP.NET Web API教程]4.1 ASP.NET Web API中的路由 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 4.1 Routing in ASP.NET Web API 4.1 ASP.NET Web API中的路由 本文引自:http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

ASP.NET Web API中的Http请求路由选择

问题描述 我在CSDN上发表了一篇博客,翻译了ASP.NETWebAPI的路由策略,欢迎各位参与讨论: 解决方案 解决方案二:多谢分享~~~~~~~~~~

Asp.Net Web API 2第十一课——在Web API中使用Dependency Resolver

原文:Asp.Net Web API 2第十一课--在Web API中使用Dependency Resolver 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文主要来介绍在Asp.Net Web API使用Web API的Decpendency Resolver在控制器中如何注入依赖. 本文使用VS2013.本文的示例代码下载链接为http://pan.baidu.