IoC在ASP.NET Web API中的应用

时间:2022-05-12 06:43:57

控制反转(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: }