從MVC3中就開始接觸Ninject這個IOC工具。也一直是MVC Framework系列書籍中推薦的IOC工具,固然還有優秀的Autofac等。性能和使用上面個有千秋。下面先看一下Ninject的使用: html
1.添加Ninject。工具-->Nuget程序包管理器-->程序包管理器控制檯,輸入下面的命令:bootstrap
Install-Package Ninject -version 3.0.1.10
Install-Package Ninject.Web.Common -version 3.0.0.7 Install-Package Ninject.MVC3 -Version 3.0.0.6
2.建立依賴分解器 NinjectDependencyResolver。app
NinjectDependencyResolver實現了IDependencyResolver接口,當一個請求進來的時候,MVC框架會調用GetService或GetServices方法去獲取對象的實例去服務這個請求。GetAll方法支持單個類型的多重綁定。咱們在AddBinds方法中添加接口的綁定。框架
public class NinjectDependencyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependencyResolver(IKernel kernelParam) { kernel = kernelParam; AddBindings(); } public object GetService(Type serviceType) { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return kernel.GetAll(serviceType); } private void AddBindings() {
kernel.Bind<IProductRepository>().To<EFProductRepository>();
kernel.Bind<IAuthProvider>().To<FormsAuthProvider>();ide
}
}
3.註冊函數
在MVC3,4中,咱們是在Global的Application_Start()中註冊。當應用啓動的時候回觸發Application_Start()中的方法。工具
DependencyResolver.SetResolver(new NinjectDependencyResolver());
那再MVC5中,更加完善。注意到咱們以前引用了Ninject.Web.Common,這個是在MVC4之前沒有出場的。它會在App_Start文件中建立一個NinjectWebCommon.cs類:源碼分析
它的Start方法是會先於Global的Application_Start()方法執行。性能
[assembly: WebActivator.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")] [assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(NinjectWebCommon), "Stop")] namespace SportsStore.WebUI { public static class NinjectWebCommon { private static readonly Bootstrapper bootstrapper = new Bootstrapper(); /// <summary> /// Starts the application /// </summary> public static void Start() { DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule)); DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule)); bootstrapper.Initialize(CreateKernel); } /// <summary> /// Stops the application. /// </summary> public static void Stop() { bootstrapper.ShutDown(); } /// <summary> /// Creates the kernel that will manage your application. /// </summary> /// <returns>The created kernel.</returns> private static IKernel CreateKernel() { var kernel = new StandardKernel(); kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel); kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>(); RegisterServices(kernel); return kernel; } /// <summary> /// Load your modules or register your services here! /// </summary> /// <param name="kernel">The kernel.</param> private static void RegisterServices(IKernel kernel) { System.Web.Mvc.DependencyResolver.SetResolver(new Infrastructure.NinjectDependencyResolver(kernel)); } } }
它充分使用Asp.Net 4.0的新技術,並使用了WebActivator框架,在Web程序啓動前動態調用Start函數,在關閉前調用Stop函數.在Start函數中,動態註冊了OnePerRequestHttpModule和NinjectHttpModule.而對於CreateKernel函數,首先新建了IOC核心,而後綁定了Func<IKernel>類型與IHttpModule類型.spa
5.綁定方法:
1)基本綁定
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
2)傳遞參數:
建立一個IDiscountHelper接口。讓DefaultDiscountHelper 實現它。
public interface IDiscountHelper { decimal ApplyDiscount(decimal totalParam); } public class DefaultDiscountHelper : IDiscountHelper { public decimal DiscountSize { get; set; } public decimal ApplyDiscount(decimal totalParam) { return (totalParam - (DiscountSize / 100m * totalParam)); }
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50M);
也能夠從構造函數傳遞參數:
public class DefaultDiscountHelper : IDiscountHelper { public decimal discountSize; public DefaultDiscountHelper(decimal discountParam) { discountSize = discountParam; } public decimal ApplyDiscount(decimal totalParam) { return (totalParam - (discountSize / 100m * totalParam)); } }
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam", 50M);
3)條件綁定
有時候咱們一個接口,有不一樣的實現對象。這個時候咱們須要根據使用狀況來獲取相應的實例。咱們再建立一個FlexibleDiscountHelper來實現上面的接口。
public class FlexibleDiscountHelper : IDiscountHelper { public decimal ApplyDiscount(decimal totalParam) { decimal discount = totalParam > 100 ? 70 : 25; return (totalParam - (discount / 100m * totalParam)); } }
kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();
上面的意思就是:當注入到LinqValueCalculator的時候,綁定FlexibleDiscountHelper。這樣就方便多了。
方法 |
效果
|
When(predicate)
|
當Lambda表達式結果爲ture時使用該綁定 |
WhenClassHas<T>()
|
當被注入的對象被特性T標記時使用該綁定
|
WhenInjectedInto<T>()
|
當被注入的對象是T時使用綁定。
|
4)做用範圍
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>().InRequestScope();
InRequestScope是一個擴展方法,位於Ninject.Web.Common命名空間中,告訴Ninject,只應該爲每個Asp.Net 接受到的Http請求建立一個LinqValueCalculator實例。
方法
|
效果
|
InTransientScope()
|
默認模式,解決每次依賴的時候都會建立一個新實例。
|
InSingletonScope()
|
單例模式,貫穿整個應用。 |
ToConstant(object)
|
綁定到某個常亮。 |
InThreadScope()
|
對於單個線程建立單個實例
|
InRequestScope()
|
對於單個Http請求建立單個實例 |
這裏說明下ToConstant,對於某個接口,咱們實現好了一個對象,能夠用ToConstant方法來綁定
好比咱們用moq實現了接口IProductRepository,這樣在使用到這個接口的地方,注入的實例中就已經含有了三個Product對象,至關於已經初始化好了。
var mock=new Mock<IProductRepository>(); mock.Setup(m => m.Products).Returns(new List<Product> { new Product {Name = "Football", Price = 25}, new Product {Name = "Surf board", Price = 179}, new Product {Name = "Running shoes", Price = 95} }); kernel.Bind<IProductRepository>().ToConstant(mock.Object);
小結:IOC在MVC中應用的不少,有必要選擇一款適合本身須要的IOC框架。但願本文對你有幫助。
參考文章:NinJect 源碼分析: http://www.verydemo.com/demo_c360_i40786.html
IOC 框架性能比較:http://www.cnblogs.com/liping13599168/archive/2011/07/17/2108734.html
小牛之路 Ninject:http://www.cnblogs.com/willick/p/3299077.html