Ninject是一個快如閃電、超輕量級的基於.Net平台的依賴注入架構。它能夠協助你把應用程式分離成一個個松耦合、高內聚的模組,然後用一種靈活的方式組裝起來。通過使用Ninject配套你的軟體架構,那麼代碼將會變得更加容易編寫、重用性強、易於測試和修改。
MVC4 配合 Ninject 3 更是如虎添翼。
1.問題情境
在 MVC 的開發中,我們通常會使用到背景資料,比如說需要擷取一個背景資訊。通常會定義一個訪問資訊的介面,然後,有一個類實現了這個介面。
public interface IMessageProvider{ string GetMessage();}public class NinjectMessageProvider : IMessageProvider{ public string GetMessage() { return "This message was provided by Ninject"; }}
在控制器中,經常會出現這樣的代碼。
public class HomeController : Controller{ private IMessageProvider MessageProvider { set; get; } public HomeController() { this.MessageProvider = new NinjectMessageProvider(); } public ActionResult Index() { string message = this.MessageProvider.GetMessage(); return View( (object) message); } ......}
這裡使用了建構函式來建立提供器對象執行個體。問題是,在網站中,我們會出現大量的 Controller,那麼,在每個 Controller 中我們都需要寫這樣的代碼,進一步講,如果我們以後需要建立的提供器物件類型不再是 NinjectMessageProvider 類型了,就會導致大量的修改。
使用 NInject 可以讓這些問題迎刃而解。
2. 擷取 NInject
:http://www.ninject.org/
第一種方式是常用的引用程式集方式,首先到官方網站下載,注意有多種版本。
解壓之後,你會得到一個名為 Ninject.dll 的程式集,將它引用到你的項目中。
還有一種方式,是使用 Visual Studio 支援的 NuGet,使用這個工具可以直接幫你從網上下載相應的程式集並引用到項目中。
3. 簡單使用
首先,開啟控制器的代碼檔案,在前面使用 using 引用 Ninject 命名空間,這裡使用了擴充方法。
using Ninject;
然後,將建構函式修改為如下所示:
public HomeController(){ Ninject.IKernel ninjectKernel = new Ninject.StandardKernel(); ninjectKernel.Bind<IMessageProvider>() .To<NinjectMessageProvider>(); this.MessageProvider = ninjectKernel.Get<IMessageProvider>();}
這裡的 Ninject.IKernel 是 Ninject 的核心。
4. 使用依賴注入
在每個控制器中,都這樣建立對象,還不如原來方便,好在 MVC 提供了依賴注入的入口,我們將現在的建構函式修改一下,支援建構函式注入。
public HomeController(IMessageProvider provider){ this.MessageProvider = provider;}
然後,建立一個 NinjectDependencyResolver,實現 MVC 中提供的注入介面 IDependencyResolver,如下所示。
using System;using System.Collections.Generic;using System.Linq;using System.Web;using Ninject;using MvcApplication1.Controllers;namespace MvcApplication1{ public class NinjectDependencyResolver :System.Web.Mvc.IDependencyResolver { private Ninject.IKernel kernel; public NinjectDependencyResolver() { this.kernel = new Ninject.StandardKernel(); this.AddBindings(); } private void AddBindings() { this.kernel.Bind<IMessageProvider>() .To<NinjectMessageProvider>(); } public object GetService(Type serviceType) { return this.kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType) { return this.kernel.GetAll(serviceType); } }}
不要忘記第三步,註冊這個容器。在 Global.asax 中,添加如下代碼。
System.Web.Mvc.DependencyResolver.SetResolver( new MvcApplication1.NinjectDependencyResolver());AreaRegistration.RegisterAllAreas();WebApiConfig.Register(GlobalConfiguration.Configuration);FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);RouteConfig.RegisterRoutes(RouteTable.Routes);
重新運行程式,你會發現控制器已經能夠直接擷取訊息提供器對象了。
在 MVC 擷取控制器對象的時候,會發現需要為建構函式傳遞一個實現介面 IMessageProvider 的對象執行個體,Ninject 發現已經註冊的類型為 NinjectMessageProvider,那麼,Ninject 就會自動協助我們建立一個對象執行個體,再將這個對象執行個體傳遞到控制器中。
5. 使用屬性注入
如果控制器中沒有使用建構函式注入,而是使用了屬性注入呢?完全沒有問題,你只需要標註一個特性。注意:這個屬性的範圍必須是 public 的。
[Ninject.Inject]public IMessageProvider MessageProvider { set; get; }
什嗎?你的這個成員是 private 的?沒有問題,設定一下,讓 Ninject 也可以注入非公用的成員就可以了。
public NinjectDependencyResolver(){ this.kernel = new Ninject.StandardKernel(); this.kernel.Settings.InjectNonPublic = true; this.AddBindings();}
這樣,下面的成員也可以注入。
[Ninject.Inject]private IMessageProvider MessageProvider { set; get; }