依賴注入:Ninject學習筆記


依賴注入(DI)就不多說了,可以自行百度,本筆記整理自Pro ASP.NET MVC5。

1,Ninject安裝

Ninject是一個開源的注入容器,可以通過VS的Nuget進行安裝。由於是在mvc中應用,需要安裝下面3個類庫。

  • Ninject
  • Ninject.Web.Common
  • Ninject.Web.Mvc

2,簡單使用

在沒有用DI之前,我們通常是這樣寫的。

        // GET: Home
        public ActionResult Index()
        {
            IValueCalculator calc = new LinqValueCalculator();

            ShoppingCart cart = new ShoppingCart(calc);
            cart.Products = products;

            decimal totalValue = cart.CalulateProductTotal();

            return View(totalValue);
        }

我們的目標是,不去new LinqValueCalculator,這樣才會消除依賴,於是利用Ninject變成下面這樣。

        public ActionResult Index()
        {

            IKernel ninjectKernel = new StandardKernel();
            ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
            IValueCalculator calc = ninjectKernel.Get<IValueCalculator>();

            ShoppingCart cart = new ShoppingCart(calc);
            cart.Products = products;

            decimal totalValue = cart.CalulateProductTotal();

            return View(totalValue);
        }

簡單的3句代碼,建立起了IValueCalculator和LinqValueCalculator之間的映射關系,然后調用Get方法獲得實例。

這樣做了之后,我們就不用再new了,但是這遠遠不夠,Controler類中依然存在LingValueCalculator和額外的Ninject的類,

我們需要把這些代碼移出Controler類。

3,改進Ninject,達到真正的解耦

1)在Controler的構造函數中傳入IValueCalculator

    public class HomeController : Controller
    {
        private IValueCalculator calc;
        private Product[] products = {
            new Product {Name = "Kayak", Category = "Watersports", Price = 275M },
            new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M },
            new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.5M },
            new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M }
        };

        public HomeController(IValueCalculator calc)
        {
            this.calc = calc;
        }

        // GET: Home
        public ActionResult Index()
        {
            ShoppingCart cart = new ShoppingCart(calc);
            cart.Products = products;

            decimal totalValue = cart.CalulateProductTotal();

            return View(totalValue);
        }
    }

難道構造函數中的IValueCalculator會自動初始化?是的,這就是Ninject幫你做的,但必須先按照下面這樣做。

2)實現IDependecyResolver接口,這個接口是MVC自帶的,不是Ninject的。實現了這個接口,MVC框架才會自動按照上面那樣創建對應接口的實例。

    public class NinjectDependencyResolver : IDependencyResolver
    {
        private IKernel kernal;

        public NinjectDependencyResolver(IKernel kernalParam)
        {
            kernal = kernalParam;
            AddBindings();
        }
        public object GetService(Type serviceType)
        {
            return kernal.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernal.GetAll(serviceType);
        }

        public void AddBindings()
        {
            kernal.Bind<IValueCalculator>().To<LinqValueCalculator>().InRequestScope();
            kernal.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discount", 10m);
            kernal.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();
        }
    }

GetService和GetServices是接口的方法,大致就是傳入一個接口類型,然后傳出去一個實例。

你完全可以自己簡單的實現這兩個方法,但是Ninject畢竟是經受了考驗的,各種配置齊全的DI容器,本文的主旨也就是介紹Ninject,所以用Ninject實現這兩個方法。

具體就是上面這樣,所有的映射關系放在了AddBinding這個方法中,以后只用修改這個方法,就可以全局改變不同的實現。

3)NinjectDependencyResolver的初始化

上面的這個NinjectDependencyResolver需要初始化,在添加Njinect類庫的時候,在App_Start下,生成了一個NinjectWebCommon.cs文件,其中有一個RegisterServices方法,

這個方法會在應用程序初始化的時候調用,所以我們就在這里初始化我們的NinjectDependencyResolver。

    public static class NinjectWebCommon 
    {
      。。。
        /// <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
                EssentialTools.Infrastructure.NinjectDependencyResolver(kernel));
        }
    }

好了,到此為止,我們就可以在Controler這個類的構造函數任意的傳人需要使用的接口,只要在NinjectDependencyResolver中添加對應的映射,Ninject就會自動的幫我們創建好。

4)Ninject不是簡單的new,它可以在建立映射的時候配置不同的選項,下面例舉幾個重要的配置選項。

  • 創建對象的生命周期的控制
kernal.Bind<IValueCalculator>().To<LinqValueCalculator>().InRequestScope();
  • 創建對象的構造函數參數的設置(屬性值也可以設置)
kernal.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discount", 10m);
  • 建立的映射的適用條件
kernal.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();
  • 實例初始化時,又依賴於其他接口時,Ninject會把依賴的所有接口一並初始化,這一點我們自己實現的話可能會比較困難。

以上就是Ninject的簡單介紹,更加詳盡的功能,可以查閱相關文檔。另外,微軟自帶的Utinity也是和Ninject相似的DI容器,有了Ninject的使用經驗,

再用其他的DI容器應該也不是很困難。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM