MVC框架之因此如此受歡迎的緣由之一就是它十分注意支持關注分離,使各個功能部件儘可能可以相互獨立。今天咱們就來看看MVC4如何使用DI方法實現一些組件的獨立,使原本結合緊密的部件,鬆耦合。我如今所說的對於.net的一些初學者來講可能有點拗口,其實我也是一個實打實的初學者,本身開始看這段話的時候遲遲不能理解,可是當看了實例以後,消化了一下就還算是懂得了其中的一些韻味了。下面就讓我來和你們分享一下我本身所理解的依賴性注入。但願你們能多指教。瀏覽器
那麼接下來咱們來看一個簡單的例子,用Demo說話mvc
咱們新建一個MVC4的項目吧框架
而後選擇Basic模板函數
點擊Ok建立好項目this
接着在Models文件夾添加一個IEmailSender接口,代碼以下spa
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DIShow.Models { public interface IEmailSender { public string SendEmail(); } }
接着再添加一個EmailSender類實現IEmailSender接口,代碼以下.net
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace DIShow.Models { public class EmailSender:IEmailSender { public string SendEmail() { return "My Name is SendEmail,My Type is EmailSender"; } } }
如今咱們在Controller文件夾裏添加一個HomeControllercode
咱們要實現的功能就是在Controller裏調用SendEmail方法來發送一個郵件。對象
咱們在controller裏添加以下代碼就能夠了。blog
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using DIShow.Models; namespace DIShow.Controllers { public class HomeController : Controller { private IEmailSender emailSender; public string Index() { emailSender = new EmailSender(); return emailSender.SendEmail(); } } }
這個時候咱們運行程序,就能夠看到瀏覽器裏的輸出
如今咱們惟一能夠肯定的就是這個程序時正確的。
那麼如今咱們就來談談這樣簡單的一個程序能夠怎樣作,來讓他更爲合理,具備清晰的結構。
首先咱們能夠看到,咱們有一個接口和一個實現這個接口的類,確定有同窗會想問,就這樣的程序幹嗎還要畫蛇添足搞個接口,直接在controller裏面實例化這個類,再調用SendEmail方法就行了。我想說的是,接口只是爲了後面的改進作一個鋪墊,如今看來確實是無關緊要。
而後如今我提出一個問題,要是我有多個發送郵件的程序,也就是說有多個相似於EmailSender這樣的類。要是我想換一個發送程序,豈不是我每次必需要修改控制器中的代碼,以此來切換髮送程序。這樣的作法對於很小的程序來講還好,對於稍微大一點的程序就會變得很不合理。這樣就把控制器的代碼變得十分繁瑣了。並且對於MVC程序來講控制器就至關於大腦,你不能老是修改大腦,最合理的方式就是修改提供程序,而後大腦只須要一個調用執行該方法的接口就好了,並不須要關心具體是怎麼實現的。回到咱們如今的例子,咱們要實現的效果就是在controller裏面不出現EmailSender,只須要一個IEmailSender接口。咱們只須要實例化這個接口的具體實現就好了。因此咱們能夠對控制器中的代碼進行以下改進
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using DIShow.Models; namespace DIShow.Controllers { public class HomeController : Controller { private IEmailSender emailSender; public HomeController(IEmailSender emailSender) { this.emailSender = emailSender; } public string Index() { return emailSender.SendEmail(); } } }
咱們能夠看到這時咱們就實現了HomeController和EmailSender之間毫無聯繫,固然這樣的程序時沒辦法運行的,由於程序並不知道如何實例化IEmailsender這個接口,雖然有一個實現了這個接口的類,可是咱們並無告訴程序應該用哪一個類去實例化這個接口。因此接下來咱們就要去告訴程序應該用哪一個類去實例化這個接口。
解決問題的方法就是「DI容器」,這個容器就是在接口(例如IEmailSender)和實現接口的具體類(例如EmailSender)之間擔任一個中間人,由他來處理具體經過實例化哪一個類來實例化接口。
而DI容器應該如何實現呢,兩種方法,第一種就是本身建立一個DI容器,第二種就是用網上的開源代碼,本人用的是Ninject包,網址:http://www.ninject.org
而在本篇博客中,因爲做者本人能力有限,因此將只演示第二種方法。
你們能夠在我提供的網址上看一下該包的具體細節而後下載包來進行使用,也能夠直接在VS中的引用中進行安裝。以下圖
安裝好後接下來咱們就開始用使用這個包來幫助咱們建立DI容器
第一步:建立一個依賴性鏈解析器
這個解析器就是相似搞出一箇中介,讓程序知道哪個類去實例化哪個接口。咱們能夠在mvc項目中,新建一個文件夾,例如Infrastructure,而後在裏面建一個類:NinjectDependencyResolver 並實現IDependencyResolver接口,代碼以下
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Ninject; using System.Web.Mvc; using DIShow.Models; namespace DIShow.Infrastructure { public class NinjectDependenceyResolver : IDependencyResolver { private IKernel kernel; public NinjectDependenceyResolver() { kernel = new StandardKernel(); AddBindings(); } public object GetService(Type serviceType)//IDependencyResolver的方法 { return kernel.TryGet(serviceType); } public IEnumerable<object> GetServices(Type serviceType)//IDependencyResolver的方法 { return kernel.GetAll(serviceType); } private void AddBindings() { kernel.Bind<IEmailSender>().To<EmailSender>(); } } }
第二步:註冊依賴解析器
經過註冊依賴解析器來告訴MVC框架,用戶但願使用本身的依賴解析器,那麼在哪裏註冊呢,固然是在管理整個程序運行的地方註冊-Global.asax.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using DIShow.Infrastructure; namespace DIShow { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); DependencyResolver.SetResolver(new NinjectDependenceyResolver()); } } }
DependencyResolver.SetResolver(new NinjectDependenceyResolver())便實現了註冊
經過以上兩步DI容器的建立和註冊就已經搞定了。
如今咱們的這個小項目的依賴性注入就徹底搞定了,咱們來運行程序檢測一下正確與否
事實說明是正確的。
最後咱們仍是來簡單總結一下吧。
首先咱們來梳理一下程序的運行過程:程序啓動,根據路由系統咱們到了HomeController,而後運行到HomeController構造函數的時候發現須要傳入一個IEmailSender的實例化對象。這個時候程序回到Global當中,發現Global確實註冊這樣一件事,就是咱們指定了怎樣去實例化接口。經過咱們的註冊信息,咱們找到了咱們的DI容器,也就是NinjectDependenceyResolver類。而後咱們在這個類裏面傳入一個類型給GetService,而後它經過查看咱們的綁定信息,這個中介就發現咱們是把IEmailSender綁定到EmailSender上面去的。因而就 實例化了EmailSender獲得了一個對象,最後返回給了在HomeController中的構造函數中的參數sendEmail。因而後面就能夠成功執行方法了。
而後咱們來看一下實現這些過程主要作了那幾步:
1.寫出接口和實現類。
2.在控制器中只調用接口方法,不出現具體類
3.建立一個DI容器,將接口和具體類綁定
4.在Global中註冊這個容器
就這樣四步就搞定了。之後要是想要切換另外一個發送程序,只須要在DI容器中將接口綁定到另外一個實際類上就能夠了,控制器不須要作任何修改。
好啦,個人分享就到此爲止了,之後要是學到了更多有意思的東西還會和你們繼續分享的。