ASP.NET Web API 框架研究 IoC容器 DependencyResolver
一、概念
1、IoC(Inversion of Control),控制反转
即将依赖对象的创建和维护交给一个外部容器来负责,而不是应用本身。如,在类型A中需要使用类型B的实例,而B的实例的创建不是由A负责,而是由外部容器来创建。
2、DI(Dependency Injection),依赖注入
即外部容器在运行时候动态的将依赖类型的实例对象注入到应用中。其与IoC联系一起,因为IoC才需要DI。当然,实例对象也可以直接调用IoC容器的方法(如GetService)获得。DI分三种形式:
- 构造函数注入(Constructor Injection):构造函数的参数定义为一个抽象依赖类型,IoC容器在调用A的构造函数创建对象之前会解析注册的依赖关系并创建对应的依赖类型的实例。
public A(IB b)
{
_b = b;
}
- 属性注入(Property Injection):在对象A被IoC容器创建时候,Ioc容器自动通过Set对该属性赋值为该类型(B)注册的实例对象;用Unity时候,属性要标注[Dependency]特性
[Dependency]
public IB B { get; set; }
- 方法注入(Method Injection):在对象A被IoC容器创建时候,自动调用方法;用Unity时候,方法要标注[InjectionMethod]特性
[InjectionMethod]
public void SetInjection(IB b)
{
_b = b;
}
3、IoC容器
负责根据依赖类型注册的类型创建实例对象,解决对象之间的抽象依赖关系,用来返回服务接口类型服务实例。
二、DependencyReslover
是ASP.NET Web API内部使用的一个IoC容器;它继承IDependencyReslover接口,其又继承IDependencyScope ,默认实现是EmptyResolver ,相当于默认是没有IoC容器功能,不能返回任何类型的实例。涉及的类,如下图:
源代码如下:
public interface IDependencyScope : IDisposable { object GetService(Type serviceType); IEnumerable<object> GetServices(Type serviceType); }
public interface IDependencyResolver : IDependencyScope { IDependencyScope BeginScope(); }
internal class EmptyResolver : IDependencyResolver { private static readonly IDependencyResolver _instance = new EmptyResolver(); private EmptyResolver() { } public static IDependencyResolver Instance { get { return _instance; } } public IDependencyScope BeginScope() { return this; } public void Dispose() { } public object GetService(Type serviceType) { return null; } public IEnumerable<object> GetServices(Type serviceType) { return Enumerable.Empty<object>(); } }
另外,EmptyResolver 的指定,不是在ServicesContainer,而是直接在HttpConfiguration里指定,如下代码段
三、自定义扩展IDependencyReslover
EmptyResolver没有IoC功能,想要使用IoC的功能,必须自定义扩展IDependencyReslover,该接口是ASP.NET Web API和IoC工具的桥梁,工具如Unity,Ninject
1、使用Unity
public class UnityResolver : IDependencyResolver { protected IUnityContainer container; public UnityResolver(IUnityContainer container) { if (container == null) { throw new ArgumentNullException("container"); } this.container = container; } public object GetService(Type serviceType) { try {
if(container.IsRegistered(serviceType))
{ return container.Resolve(serviceType);
}
else
{
return null;
}
} catch (ResolutionFailedException) { return null; } } public IEnumerable<object> GetServices(Type serviceType) { try {
if(container.IsRegistered(serviceType))
{
return container.ResolveAll(serviceType);
}
else
{
return new List<object>();
}
} catch (ResolutionFailedException) { return new List<object>(); } } public IDependencyScope BeginScope() { var child = container.CreateChildContainer(); return new UnityResolver(child); } public void Dispose() { container.Dispose(); } }
注册:
public static void Register(HttpConfiguration config) { var container = new UnityContainer();
//如果GetService没有IsRegistered判断,可以不用注册,直接可以根据Type获取实例 container.RegisterType<ProductController>(); container.RegisterType<IProductRepository, ProductRepository>(); config.DependencyResolver = new UnityResolver(container); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
2、使用Ninject
public class NinjectDependencyResolver : IDependencyResolver { private List<IDisposable> disposableServices = new List<IDisposable>(); public IKernel Kernel { get; private set; } public NinjectDependencyResolver(NinjectDependencyResolver parent) { this.Kernel = parent.Kernel; } public NinjectDependencyResolver() { this.Kernel = new StandardKernel(); } public void Register<TFrom, TTo>() where TTo : TFrom { this.Kernel.Bind<TFrom>().To<TTo>(); } public IDependencyScope BeginScope() { return new NinjectDependencyResolver(this); } public object GetService(Type serviceType) { return this.Kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { foreach (var service in this.Kernel.GetAll(serviceType)) { this.AddDisposableService(service); yield return service; } } public void Dispose() { foreach (IDisposable disposable in disposableServices) { disposable.Dispose(); } } private void AddDisposableService(object servie) { IDisposable disposable = servie as IDisposable; if (null != disposable && !disposableServices.Contains(disposable)) { disposableServices.Add(disposable); } } }
注册:
NinjectDependencyResolver dependencyResolver = new NinjectDependencyResolver(); dependencyResolver.Register<IContactRepository, DefaultContactRepository>(); GlobalConfiguration.Configuration.DependencyResolver = dependencyResolver;