当前位置: 澳门新濠3559 > 编程 > 正文

首先设计类来实现接口,本次将考察三类工具

时间:2019-12-08 22:39来源:编程
IoC框架最本质的东西:反射或许EMIT来实例化对象。然后大家能够增进缓存,或然部分战略来决定指标的生命周期,举个例子是或不是是单例对象依旧每回都生成五个新的靶子。 作者:

IoC框架最本质的东西:反射或许EMIT来实例化对象。然后大家能够增进缓存,或然部分战略来决定指标的生命周期,举个例子是或不是是单例对象依旧每回都生成五个新的靶子。

作者:[美]Adam Freeman      来源:《精通ASP.NET MVC 4》

本次将观望三类工具,它们是每一人 MVC 技术工作者具库的积极分子:DI容器、单元测验框架和模拟工具。

1.成立二个演示项目

制造一个空 ASP.NET MVC 4 项目 EssentiaTools 。

 

1.1 创立模型类

在 Models 文件夹下新建 Product.cs 类文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class Product
    {
        public int ProductID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public string Catogory { get; set; }
    }
}

其余,再新建 LinqValueCalculator.cs 类文件,它将总计 Product 对象会集的总价值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class LinqValueCalculator : IValueCalculator
    {
        public decimal ValueProducts(IEnumerable<Product> products)
        {
            return products.Sum(p=>p.Price);            
        }
    }
}

 

继之,再新建一个模型类 ShoppingCart ,它象征了 Product 对象的联谊,何况应用 LinqValueCalculator 来鲜明总共价值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class ShoppingCart
    {
        private IValueCalculator calc;

        public ShoppingCart(IValueCalculator calcParam) {
            calc = calcParam;
        }

        public IEnumerable<Product> Products { get; set; }

        public decimal CalcularProductTotal() {
            return calc.ValueProducts(Products);
        }
    }
}

 

1.2 加多调控器

在 Controller 文件夹下新建调整器文件 HomeController.cs

using EssentiaTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EssentiaTools.Controllers
{
    public class HomeController : Controller
    {
        private Product[] products = { 
        new Product{Name="Kayak",Catogory="Watersports",Price=275M}, 
        new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M}, 
        new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
        new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
        };
        public ActionResult Index()
        {
            LinqValueCalculator calc = new LinqValueCalculator();
            ShoppingCart cart = new ShoppingCart(calc) { Products = products };
            decimal totalValue = cart.CalcularProductTotal();
            return View(totalValue);
        }
    }
}

 

1.3 加多视图

据说动作方法,创制对应的视图像和文字件 Index.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Value</title>
</head>
<body>
    <div>
        Total value is $@Model
    </div>
</body>
</html>

运作程序,效果如下:

图片 1

2.使用 Ninject

Ninject 是大家所喜好的DI容器,它总结、高雅且易用。

DI容器,其观念是对MVC 应用程序中的组件实行解耦,那是因此接口与DI 相结合来促成的。

 

2.1 精通难题

在前头示例中,布局了二个力所能致用 DI 解决的难点。该品种重视于一些紧耦合的类:ShoppingCart 类与 LinqValueCalculator 类是紧耦合的,而 HomeController 类与 ShoppingCart 和 LinqValueCalculator 都以紧耦合的。那代表,假诺想替换 LinqValueCalculator 类,就亟须在与它有紧耦合关系的类中寻觅对它的引用,并举行改过。对这种总结的档案的次序以来,那不是主题材料。可是,在多少个实际上项目中,那或然会产生二个单调且易错的进度,尤其是,假诺想在八个不一样的计算器达成之间开展切换,而不只是用另一个类来替换另二个类的场合下。

 

应用接口

透过利用 C# 接口,从计算器的得以达成中架空出其效果定义,能够减轻一些难题。在 Models 文件夹下增多接口文件 IValueCalculator:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EssentiaTools.Models
{
    public interface IValueCalculator
    {
        decimal ValueProducts(IEnumerable<Product> products);
    }
}

下一场,能够在 LinqValueCalcular 类中贯彻那一接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class LinqValueCalculator: IValueCalculator
    {
        public decimal ValueProducts(IEnumerable<Product> products)
        {
            return products.Sum(p=>p.Price);            
        }
    }
}

该接口能够打断 ShoppingCart 与 LinqValueCalcular 类之间的紧耦合关系,将该接口运用于 ShoppingCart 类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class ShoppingCart
    {
        private IValueCalculator calc;

        public ShoppingCart(IValueCalculator calcParam) {
            calc = calcParam;
        }

        public IEnumerable<Product> Products { get; set; }

        public decimal CalcularProductTotal() {
            return calc.ValueProducts(Products);
        }
    }
}

 在上述进度中,已经去掉了 ShoppingCart 与 LinqValueCalculator 之间的耦合,因为在选择 ShoppingCart时,只要为其布局器传递一个IValueCalculator 接口对象就能够了。于是,SHoppingCart 类与 IValueCalculator 的兑现类之间不再有平昔挂钩,不过C# 须要在接口实例化时要求钦赐其达成类。那很当然,因为它须要掌握客户想用的是哪一个落实类。这象征,Home 调节器在成立 LinqValueCalculatoe 对象时仍然有标题。

...
public ActionResult Index(){
            IValueCalculator calc = new LinqValueCalculator();
            ShoppingCart cart = new ShoppingCart(calc) { Products = products };
            decimal totalValue = cart.CalcularProductTotal();
            return View(totalValue);
}
...

应用 Ninject 的目标正是要消除这一问题,用以对 IValueCalculator 接口的落实进行实例化,但所需的完成细节却又不是 Home 调控器代码的大器晚成局部(即,通过 Ninject,能够去掉 Home 调控器中的那行黑体语句所示的代码,那项职业由 Ninject 完结,那样便去掉了 Home 调整器与总的价值总括器 LinqValueCalculator 之间的耦合)

 

2.2 将 Ninject 添加到 Visual Studio 项目

透过工具菜单找到 “处明白决方案的 NuGet 程序包”选项,加多 Ninject:

图片 2图片 3

 

要么直接右击项目名,找到 “管理 NuGet 程序包” 选项也足以增添 Ninject

图片 4

首先设计类来实现接口,本次将考察三类工具。 

2.3 Ninject 初步

为了得到 Ninject 的基本效能,要做的办事有多个步骤。给 Index 动作方法增加基本的 Ninject 成效代码如下:

 

using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EssentiaTools.Controllers
{
    public class HomeController : Controller
    {
        private Product[] products = { 
        new Product{Name="Kayak",Catogory="Watersports",Price=275M}, 
        new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M}, 
        new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
        new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
        };
        public ActionResult Index()
        {
            //第一步,准备使用 Ninject,创建一个 Ninject 内核的实例。
            //这是一个对象,它与Ninject 进行通信,并请求接口的实现。
            IKernel ninjectKernel = new StandardKernel();

            //第二步,建立应用程序中的接口和想要使用的实现类之间的关系
            //Ninject 使用C# 的类型参数创建了一种关系:
            //将想要使用的接口为 Bind 方法的类型参数,并在其返回的结果上调用To 方法。
            //将希望实例化的实现类设置为 To 方法的类型参数。 
            //该语句告诉 Ninject:
            //当要求它实现 IValueCalculator 接口时,应当创建 LinqValueCalculator 类的新实例,以便对请求进行服务。
            ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();

            //第三步,实际使用 Ninject,通过其 Get 方法完成这一工作。
            //Get 方法所使用的类型参数告诉 Ninject ,用户感兴趣的是哪一个接口,
            //而该方法的结果是刚才用 To 方法指定的实现类型的一个实例。
            IValueCalculator calc = ninjectKernel.Get<IValueCalculator>();


            ShoppingCart cart = new ShoppingCart(calc) { Products = products };
            decimal totalValue = cart.CalcularProductTotal();
            return View(totalValue);
        }
    }
}

 

 

 

2.4 构造建设MVC 正视性注入

地点Index 动作方法所显示的八个步骤的结果是:在 Ninject 中已经济建设立了部分连锁的学识,固然用哪三个贯彻类来变成对 IValueCalculator 接口的乞请。然则,应用程序未做别的改过,因为 Home 调控器与 LinqValueCalculator 类仍是紧耦合的。

 

开创信赖深入深入分析器

示范要做的首先个修正时成立四个自定义的依靠深入分析器。MVC 框架供给接受信赖深入解析器来创建类的实例,以便对乞求举办服务。通过创办自定义解析器,保障每当要创制四个对象时,便采用Ninject 。

在档案的次序中增多新文件夹 Infrastructure ,并累积二个类公事 NinjectDependencyResolver.cs

using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EssentiaTools.Infrastructure
{
    public class NinjectDependencyResolver:IDependencyResolver
    {
        private IKernel kernel;

        public NinjectDependencyResolver() {
            kernel = new StandardKernel();
            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<IValueCalculator>().To<LinqValueCalculator>();
        }

    }
}

MVC  框架在需求二个类实例以便对叁个传来的央求举办服务时,会调用GetService 或 GetServices 方法。重视解析器要做的做事就是成立这风流倜傥实例 —— 那是后生可畏项要通过 Ninject 的 TryGet 和 GetAll 方法来达成的义务。 TryGet 方法的劳作章程接近于前方所用的Get 方法,但当未有适当的绑依期,它会重临null ,实际不是抛出分外。GetAll 方法协理对纯粹类型的七个绑定,当三个分化的劳动提供器可用时,能够使用它。

上述注重深入解析器类也是雏鹰展翅 Ninject 绑定的地点。在AddBindings 方法中,本例用Bind 和 To 方法创制了 IValueCalculator 接口和 LinqValueCalculator 类之间的关系。

 

登记依赖拆解深入分析器

必须告诉 MVC 框架,客户期望利用本身的看重分析器,那一件事可以由此匡正Global.asax 文件来完毕。

using EssentiaTools.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace EssentiaTools
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            //通过这里添加的语句,能让 Ninject 来创建 MVC 框架所需的任何对象实例,
            //这便将 DI 放到了这一示例应用程序中
            DependencyResolver.SetResolver(new NinjectDependencyResolver());

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

 

重构 Home 控制器

最后八个步骤是重构 Home 调控器,以使它亦可利用前面所创造的工具。

using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EssentiaTools.Controllers
{
    public class HomeController : Controller
    {
        private Product[] products = { 
        new Product{Name="Kayak",Catogory="Watersports",Price=275M}, 
        new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M}, 
        new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
        new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
        };

        private IValueCalculator calc;

        public HomeController(IValueCalculator calcParam)
        {
            calc = calcParam;
        }

        public ActionResult Index()
        {
            ShoppingCart cart = new ShoppingCart(calc) { Products = products };
            decimal totalValue = cart.CalcularProductTotal();
            return View(totalValue);
        }
    }
}

所做的注重订正时增添了一个结构器,它选取 IValueCalculator 接口的兑现。示例并未有一些名想要使用的是哪叁个得以达成,并且已经加多了叁个名字为“calc”的实例变量,可以在整个调节器中用它来代表布局器所吸收接纳到的 IValueCalculator 。

所做的另二个更改时去除了任何有关 Ninject 或 LinqValueCalculator 类的代码 —— 最后打破了 HomeController 和 LinqValueCalculator 类之间的紧耦合。

运转结果和前例同样:

图片 5

演示创建的是一个结构器注入示例,那是正视注入的大器晚成种样式。以下是运转示例应用程序,且 Internet Explorer 对应用程序的跟 U奔驰G级L 发送央浼时所产生的情景。

 (1卡塔尔(英语:State of Qatar)浏览器向 MVC 框架发送一个伸手 Home 的U奥迪Q3L, MVC 框架猜出该央求意指 Home 调控器,于是会成立 HomeController 类实例。

 (2卡塔尔(قطر‎MVC 框架在开创 HomeController 类实例进程中会发掘其结构器有叁个对 IValueCalculator 接口的依赖项,于是会供给依赖深入剖判器对此信任项进行剖析,将该接口钦定为依赖深入深入分析器中 GetService 方法所使用的项目参数。

 (3卡塔尔(قطر‎重视项深入分析器会将传递过来的品类参数交给 TryGet 方法,要求 Ninject 成立一个新的 IValueCalculator 接口类实例。

 (4卡塔尔(قطر‎Ninject 会检查实验到该接口与其促成类 LinqValueCalculator 具备绑定关系,于是为该接口成立贰个 LinqValueCalculator 类实例,并将其回递给正视性深入分析器。

 (5卡塔尔(قطر‎信任性深入分析器将 Ninject 所重返的 LinqValueCalculator 类作为 IValueCalculator 接口实现类实例回递给 MVC 框架。

 (6卡塔尔国MVC 框架利用信赖性拆解深入分析器再次来到的接口类实例创制 HomeController 调整器实例,并利用调节器实例度诉求实行服务。

 

那边所采取的措施其好处之一是,任何调整器都得以在其布局器中声多美滋(Dumex卡塔尔(英语:State of Qatar)个 IValueCalculator ,并透过自定义依赖性解析器使用 Ninject 来成立叁个在 AddBindings 方法中钦命的实现实例。

所得到的最大利润是,在期望用另三个落到实处来替代 LinqValueCalculator 时,只须求对信赖解析器类举行改造,因为为了满足对于 IValueCalculator 接口的央浼,这里是唯豆蔻梢头生龙活虎处为该接口钦点达成类之处。

 

成立注重性链

当须要 Ninject 创立二个档期的顺序时,它会检讨该类型与其余门类之间的耦合。就算有额外的依附, Ninject 会自动地分析那个重视性,并创制所急需的具备种类实例。

 在 Models 文件夹下新建文件 Discount.cs ,并定义了二个新的接口及其达成类:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public interface IDiscountHelper
    {
        //将一个折扣运用于一个十进制的值
        decimal ApplyDiscount(decimal totalParam);
    }

    public class DefaultDiscountHelper : IDiscountHelper
    {
        //实现接口 IDiscountHelper,并运用固定的10% 折扣
        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (10m / 100m * totalParam));
        }
    }
}

下一场在 LinqValueCalculator 类中增添二个注重,改正 LinqValueCalculator 类,以使它实施计算时利用 IDiscountHelper 接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace EssentiaTools.Models
{
    public class LinqValueCalculator : IValueCalculator
    {
        private IDiscountHelper discounter;

        public LinqValueCalculator(IDiscountHelper discountParam)
        {
            discounter = discountParam;
        }
        public decimal ValueProducts(IEnumerable<Product> products)
        {
            return discounter.ApplyDiscount(products.Sum(p => p.Price));
        }
    }
}

新加上的布局器以 IDiscountHelper 的接口完结为参数,然后将其用于 ValueProducts 方法,以便对所管理的 Products 对象的累积值运用一个折扣。

仿佛对 IValueCalculator 所做的那么,在 NinjectDependencyResolver 类中,用 Ninject 内核将 IDiscountHelper 接口与实际现类进行了绑定,将另叁个接口绑定到它的兑现:

using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace EssentiaTools.Infrastructure
{
    public class NinjectDependencyResolver:IDependencyResolver
    {
        private IKernel kernel;

        public NinjectDependencyResolver() {
            kernel = new StandardKernel();
            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<IValueCalculator>().To<LinqValueCalculator>();
            kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
        }

    }
}

 上述这风华正茂做法已经创办了二个 Ninject 能够轻巧分析的正视性链,那是经过在自定义正视性深入分析器中所定义的绑定完成的。为了满意对 HomeController 类的伸手,Ninject 会意识到它须要创建贰个用以 IValueCalculator 类的兑现,通过考查其绑定,便走访到该接口的落到实处政策是使用 LinqValueCalculator 类。但在创建 LinqValueCalculator 对象进度, Ninject 又会发觉到它需求使用 IDiscountHelper 接口完成,由此会翻动其绑定,并创办二个 DefaultDiscountHelper 对象。 Ninject 会创立那大器晚成 DefaultDiscountHelper ,并将其传递给 LinqValueCalculator 对象的布局器, LinqValueCalculator 对象又转而被传送给 HomeController 类的结构器,最终所收获的 HomeController 用于对顾客的乞请进行劳动。 Ninject 会以这种办法检查它要实例化的每三个依赖性类,不论其依据性链有多少长度,多复杂。

 

2.5 钦点属性与布局器参数值

在把接口绑定到它的落到实处时,能够提供想要运用到属性上的一些质量细节,以便对 Ninject 创设的类进行安顿。修改 DefaultDiscountHelper 类,以使它定义一个DiscountSize属性,该属性用于总计折扣量:

    public class DefaultDiscountHelper : IDiscountHelper
    {
        public decimal DiscountSize { get; set; }
        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (DiscountSize / 100m * totalParam));
        }
    }

在用 Ninject 将具体类绑定到品种时,能够接纳 WithPropertyValue 方法来安装 DefaultDiscountHelper 类中的 DiscountSize 属性的值。

        ...
        private void AddBindings()
        {
            kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
            kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize",50M);
        }
        ...

瞩目,必须提供一个字符串值作为要安装的属性名。既没有必要校正任何绑定,也无需更改使用 Get 方法得到 ShoppingCart 类实例的格局。

该属性值会遵照 DefaultDiscountHelper 的组织实行安装,并起到半价的机能。展现结果如下:

图片 6

借使要求安装七个属性值,能够链接调用 WithPropertyValue 方法包蕴全体那么些属性,也可以用布局器参数做同样的作业。能够重写 DefaultDiscountHelper 类如下,以便折扣大小作为布局器参数举办传递。

    public class DefaultDiscountHelper : IDiscountHelper
    {
        public decimal discountSize;

        public DefaultDiscountHelper(decimal discountParam)
        {
            discountSize = discountParam;
        }
        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (discountSize / 100m * totalParam));
        }
    }

为了用 Ninject 绑定那些类,能够在 AddBindings 方法中接纳WithConstructorArgument 方法来钦赐结构器参数的值:

        ...
        private void AddBindings()
        {
            kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
            kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam",50M);
        }
        ...

这一工夫允许客商将三个值注入到布局器中。相通,能够将这几个主意调用链接在一块儿,以提供多值,并与依附混合和合作。 Ninject 会决断出客商的急需,并依此来创制它。

 

2.6 使用标准绑定

Ninject 帮忙五个规格的绑定方法,那能够钦命用哪叁个类对某黄金年代一定的乞求实行响应。

在 Models 文件夹下新建类文件 FlexibleDiscountHelper.cs :

namespace EssentiaTools.Models
{
    public class FlexibleDiscountHelper : IDiscountHelper
    {

        public decimal ApplyDiscount(decimal totalParam)
        {
            decimal discount = totalParam > 100 ? 70 : 25;
            return (totalParam - (discount / 100M * totalParam));
        }
    }
}

FlexibleDiscountHelper 类依照要优惠的总额大小运用分裂的折扣,然后改良  NinjectDependencyResolver 的 AddBindings 方法,以报告 Ninject 哪天使用 FlexibleDiscountHelper ,哪天使用 DefaultDiscountHelper:

        ...
        private void AddBindings()
        {
            kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
            kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam",50M);
            kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();
        }
        ...

上述绑定指明,在 Ninejct 要将三个落到实处注入LinqValueCalculator 对象时,应该采用 FlexibleDiscountHelper 类作为 IDiscountHelper 接口的完结。

本例在妥帖的岗位留给了对 IDiscountHelper 的固有绑定。 Ninject 会尝试寻找超级相称,并且那推动对相近类或接口接纳三个暗中同意绑定,以便在条件判据无法博取知足时,让 Ninject 能够举办回滚。 Ninject 有成都百货上千不少年老成的口径绑定方法,最可行的有个别原则绑定如下:

图片 7

 

 

源码地址:https://github.com/YeXiaoChao/EssentiaTools

        每一个MVC程序员的火器库中,都有那三个工具:一个依据注入(DI卡塔尔(قطر‎容器,贰个单元测试框架,一个模仿工具。

DI达成其实很简短,首先设计类来促成接口,实际不是把具备的程序逻辑写在一个类公事中,然后大家传入三个接口和多少个世袭自接口的类作为参数,然后大家在相应的函数那将泛型参数T作为形参,伪代码:

1.预备贰个示范项目

//调用部分

        创造一个ASP.NET MVC Web Application的Empty项目,命名字为EssentialTools。

HandleDI<ITest, Test>

1.1. 创办模型类

//达成部分

        在Models文件夹下,成立Product类。

HandleDI<TInterface, T>

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

// 使用反射,EMIT,委托来实例化T创设TInterface的目的

        为了总括三个Product集合的商业事务金额,要求在Models文件夹下再增多三个LinqValueCalculator的类。

下一场我们运用反射恐怕EMIT或是委托TInterface对象。那正是DI的落到实处进程。

public class LinqValueCalculator {
    public decimal ValueProducts(IEnumerable<Product> products) {
        return products.Sum(p => p.Price);
    }
}

DI说白了,成效便是实例化世袭自接口的类

        那一个类定义了多少个称得上ValueProducts的法子,它使用Linq Sum方法,将可枚举对象中的每一个Product的Price属性的值,加在一同。

事情未发生前对DI注入与调整器增加竟然用正视性剖析器来促成,三个地点以为质疑,由于越学越不懂,越学越迷糊,因而就一时半刻放下了,接着学习,何人知道前些天写程序涉及到那些,就大浪涛沙探讨了瞬间,哪晓得,今后商量清楚起来越发顺手,思路也清晰,于是趁机,大致的掌握了一回,虽说学习是个遗忘的历程,起码本身掌握过就好...

        最终一个模子类是ShoppingCart,它代表二个Product对象的联谊,并选用三个LinqValueCalculator来调整合计值。

对于团结今后能够很好地知道那块文化,小编以为是以此原因:学习是个鲁人持竿的经过,能够一上马大家遇到标题,略作思量商量,实在可怜权且放下,继续往下走,稳步的等你学习的十足了,有了自然的学问连串,当你在遇见那样的主题素材时,你就会很好地解决它...

public class ShoppingCart {
    private LinqValueCalculator calc;
    public ShoppingCart(LinqValueCalculator calcParam) {
        calc = calcParam;
    }
    public IEnumerable<Product> Products { get; set; }
    public decimal CalculateProductTotal() {
        return calc.ValueProducts(Products);
    }
}

DI:信任性注入是生龙活虎种设计方式,用来促成程序块之间的松懈耦合
DI容器:本质上是一个智能工厂,它为相互信任的零器件提供抽象,将依附(低层模块)对象的拿到交给第三方(系统)来决定,即依靠对象不在被信任模块的类中央司法机关接通过new来获得,说白点正是创造对象的实例,况兼实例化对象的信赖。

1.2.增添调节器

调控器私下认可只可以接收无参的布局函数,但,假设我们要求为其传递参数又该如何做吗?《选择MVC基本工具Ninject解除程序类之间的耦合的简要示例》达成了(相关分析请看《MVC方式中的DI与DI容器精晓》卡塔尔。不过,有个疑问:为什么要用到DI容器来做呢?以至是依赖拆解深入分析器的主意来创设自定义调控器以落到实处调控器的重构(构造选拔参数的调控器卡塔尔?在大家常常的拍卖思路来看,应该是从其底层的兑现模块来做,最中心的正是自定义调整器,不过怎么可以够选取正视性分析器呢?

        增加一个HomeController

分析:
构造有参数的调控器,本质上是重构调整器,向原有的调节器中流入参数,那实质上正是依赖注入DI的风流罗曼蒂克种:布局器注入。我们向调整器的布局函数中传送参数使其能够担负参数:

public class HomeController : Controller {
    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.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public ActionResult Index() {
        LinqValueCalculator calc = new LinqValueCalculator();
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}
public HomeController(IValueCalculator calcParam)  
 {  
 calc = calcParam;  
 } 

1.3.增加视图

笔者们为调控器注入了大家的信赖性——IValueCalculator接口,不过,当大家调节和测量试验的时候,并不可以预知呈现出页面,相反会给大家报错,那是因为大家唯有就是流传了参数而已,调控器的当中依旧未有实行个别管理。大家应用信赖性剖析器来进展拍卖,正视性深入分析器能够用于实例化调节器。注重性剖析器有三个举足轻重零器件组成:
静态的DependencyResolver类,他对深入分析信任性扮演着静态网关成效;
IDependencyResolver接口,该接口能够由领会怎样深入分析正视性的类来实现(通过运用DI容器),何况静态的DependencyResolver将跻身该兑现进行调用,以进行其职业。
最终DI容器与依靠深入分析器就能够重构调控器以促成调控器的参数化。
能够得出结论:调控器的参数化能够用信任性深入分析器来重构调节器,是因为调整器的参数化,是运用结构器来注入的,架构器注入是依靠注入的黄金年代种格局。DI容器是亟需信任(通常是接口卡塔尔(英语:State of Qatar)的类(这里是调整器卡塔尔国和信任性的切实达成(平时是接口的继承类卡塔尔国之间的二个第三方组件.依赖性剖析器与DI容器两个相互依存

        增加一个Index视图

ASP.NET MVC的IOC注入有二种方式,也正是说我们有三种方法来重构调整器:
1.实现了IControllerFactory接口的DefaultControllerFactory;
2.实现了IDependencyResolver接口的DefaultDependencyResolver;
3.实现了IControllerActivator接口的DefaultControllerActivator;

<p>Total Price is :@Model</p>

最直白的正是自定义调整器工厂,在ASP.NET MVC 1.0时正是运用这种情势。具体的看《ASP.NET MVC使用自定义调控器工厂来落到实处IOC注入》
《MVC多个IOC注入点之Ninject使用示例》

2.使用Ninject

        注重注入(DI卡塔尔国用于对MVC程序中的各类零件解耦。通过接口和DI容器的结合,创立接口的得以完毕,进而开创两个对象的实例。何况将她们注入到结构器。

        小编在例子中有意留了叁个难点,上边我会解释它,并展现怎么用自身爱怜的Ninject那一个DI容器去消除它。

2.1.精晓那么些难点

        在实例应用中,小编创立了一个DI管理的主导难点:仅仅耦合的类。ShoppingCart类与LinqValueCalculator类牢牢耦合。HomeController类同一时间与ShoppingCart和LinqValueCalculator类牢牢耦合。

        那象征,假若本身要替换LinqValueCalculator类,笔者不能不在与它牢牢耦合的类中,找到并转移对它的援用。这对于小品种以来,不是一个主题材料。但在三个不追求虚名的花色中,如若笔者想切换不一致的calculator完结(为了测量试验、为了示例卡塔尔国,比起仅仅用八个类替换另三个类,那样的操作是意马心猿无味的,并且轻巧出错。

2.1.1.接纳叁个接口

        用接口,能够解决部分主题材料。接口定义了叁个从实例中架空出来的总括成效。在Models文件夹中,增添贰个接口。

public interface IValueCalculator {
    decimal ValueProducts(IEnumerable<Product> products);
}

        在LinqValueCalculator类中得以完成它。

public class LinqValueCalculator : IValueCalculator {
    public decimal ValueProducts(IEnumerable<Product> products) {
        return products.Sum(p => p.Price);
    }
}

        那几个接口,能够让大家破解ShoppingCart类和LinqValueCalculator类之间的严苛耦合。

public class ShoppingCart {
    private IValueCalculator calc;
    public ShoppingCart(IValueCalculator calcParam) {
        calc = calcParam;
    }
    public IEnumerable<Product> Products { get; set; }
    public decimal CalculateProductTotal() {
        return calc.ValueProducts(Products);
    }
}

        到这里,已经做了某个开展。可是C#亟需在接口最早化时期,为其制订贰个实例类。那足以理解为,因为它需求领悟小编想要使用哪个实例类。不过,那意味,在自己成立LinqValueCalculator对象时,那么些标题依然在HomeController中设有,它照旧与LinqValueCalculator类牢牢耦合着。

public ActionResult Index() {
     IValueCalculator calc = new LinqValueCalculator();
    ShoppingCart cart = new ShoppingCart(calc) { Products = products };
    decimal totalValue = cart.CalculateProductTotal();
    return View(totalValue);
}

        小编用Ninject的对象,是自己在一个地点钦命我想要实例化的IValueCalculator接口的达成,然而在HomeController的代码中,不出新要运用哪个实现的细节。

        那代表告诉Ninject,LinqValueCalculator是IvalueCalculator接口的完毕,笔者想让它使用并创新HomeController类,让该类通过Ninject得到他的对象,实际不是选拔new关键字。

2.2.添加Ninject到VS项目中

        使用NuGet包管理器,增加Ninject,Ninject.Web.Common,Ninject.MVC3那八个包到花色中。它会增多MVC3的援引,以致报错。在引用中,删除MVC3的援引,就能够在MVC5景况下周密专业。

2.3.用Ninject开始

        这里有多少个步骤,让中央的Ninject效率初始专门的学问。在HomeController中,加多对Ninject的援用,创设三个Ninject kernel的实例,用Ninject增加接口和贯彻的绑定,从Ninject得到接口的达成。

public class HomeController : Controller {
    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.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public ActionResult Index() {
        IKernel ninjectKernel = new StandardKernel();
        ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        IValueCalculator calc = ninjectKernel.Get<IValueCalculator>();
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

        第一步是筹划Ninject。创造三个Ninject kernel的实例,它用来响应用化学解倚重,并创造新对象。当自家索要叁个目的时,笔者会使用kernel,而不是new关键字。

IKernel ninjectKernel = new StandardKernel();

        通过创办StandardKernel类的新的实例,作者创设了叁个Ninjnel接口的兑现。Ninject能够被扩大和个性化,来行使差异种类的kernel,但自个儿只须要停放的斯坦dardKernel。

        第二步,是铺排Ninject kernel ,让它领会小编想利用各类接口的哪个达成。

ninjectKernel.Bind< IValueCalculator >().To< LinqValueCalculator >();

        Ninject使用C#类别参数,来创建一个关联:将Bind方法的参数,设置为自己想要使用的接口,况兼在它回到的结果上,调用To方法。作者将To方法的参数,设置为自个儿想要实例化的不胜接口的兑现类。那几个宣称告诉Ninject,在IValueCalculator接口上的注重,应该经过创办三个LinqValueCalculator类的实例来减轻。最终一步,是利用Ninject的Get方法来创制一个目的。

IValueCalculator calc = ninjectKernel.Get<IValueCalculator>() ;

        Get方法的参数,告诉Ninject,小编感兴趣的是哪些接口,况且该办法重回的结果,是本身在To方法中钦命的贯彻的二个实例。

2.4.装置MVC依赖注入

        上边呈现的多少个步骤的结果,是有关贯彻类必需被实例化来奉行Ninject中安装的IValueCalculator接口的诉求的学识。当然,大家还从未修改大家的施用,因为剩下的定义在HomeController中,那感到和HomeController依旧与LinqValueCalculator类牢牢耦合着。

        接下去,笔者博览会示什么在MVC应用的着力部分,嵌入Ninject。那会让咱们简化Controller,扩充Ninject的影响,让她贯穿整个应用。最终从调整器中移除配置。

2.4.1创造信任排除者

        笔者要做的首先个改动,是做一个自定义的信赖解决者。MVC框架使用信任消除者来创建它须求服务须求的类的实例。通过创办二个自定义的消除者,笔者能作保MVC框架,无论曾几何时他成立对象时,都选择Ninject。

        要安装消除者,笔者创立二个文件夹Infrastructure(基本功建设),用它来放不合乎放在别的文件夹下的类。在文书夹下,创设NinjectDependencyresolver类。

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<IValueCalculator>().To<LinqValueCalculator>();
    }
}

       NinjectDependencyResolver类完毕IDependencyResolver接口,那个接口是System.Mvc命名空间的一片段,何况MVC框架用它来博取需求的目的。MVC框架在她索要二个类的实例来服务传入的号召时,会调用GetService或Get瑟维斯s方法。重视消除者的天职,是因此实施TryGet和GetAll方法来创设实例。TryGet方法专门的职业办法和Get方法平日,可是当这里没有适度的绑定期,它回到null,并不是抛出叁个足够。GetAll方法帮助四个绑定到一个单纯类型,它用来当有多少个不等的落到实处目的可用时。

        笔者的依附解决者类,也是本身设置本人的Ninject binding的地点。在AddBindings方法中,笔者动用Bind和To方法,来安排IValueCalculator接口和LinqValueCalculator类之间的涉及。

2.4.2.报了名依赖解决者

        仅仅是创办二个IDependencyResolver接口的贯彻是相当不够的。Ninject包会在App_Start文件夹下创设二个称呼NinjectWebCommon的文本,它在那之中定义了前后相继运维时的automatically的办法,用来组合进ASP.NET央浼的生命周期。在NinjectWebCommon类中的RegisterServices方法,作者增多了贰个宣称,来创制一个NinjectDependencyResolver类的实例。何况应用System.Web.Mvc.DependencyResolver类中的静态方法SetResolver,使用MVC框架注册消除者。那句声明成立了Ninject和MVC框架之间的大桥,来支撑DI。

private static void RegisterServices(IKernel kernel) {
    System.Web.Mvc.DependencyResolver.SetResolver(new EssentialTools.Infrastructure.NinjectDependencyResolver(kernel));
}

2.4.3.重构HomeController

        最终一步,是重构HomeController。在前头的章节,我们吧在它里面配备了部分行业革命的工具。

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.50M},
        new  Product  {Name  =  "Corner  flag",  Category  =  "Soccer",  Price = 34.95M}
    };
    public HomeController(IValueCalculator calcParam) {
        calc = calcParam;
    }
    public ActionResult Index() {
        ShoppingCart  cart  =  new  ShoppingCart(calc)  {  Products  = products };
        decimal totalValue = cart.CalculateProductTotal();
        return View(totalValue);
    }
}

        最注重的修改,是作者在了三个构造器,让它选用三个IValueCalculator接口的兑现,退换HomeControllr类,让它声美赞臣(Meadjohnson卡塔尔(英语:State of Qatar)个依据。当Ninject创设叁个controller的实例时,Ninject会使用小编在NinjectDependencyResolver类中的配置,为controller提供二个IValueCalculator接口的达成。

        另五个更改,是移除了controller中谈到的Ninject或LinqValueCalculator类。最终,作者破坏了HomeController和LinqValueCalculator类之间密不可分耦合。

        小编早已创办了两个构造器注入的例证,它是正视注入的生机勃勃种。当你运营示例应用,并且IE央求应用的根路线时,产生的:

1.MVC框架选拔到哀求,并总结出哀告是希望参与Home调节器。

2.MVC框架央求作者自定义的重视消除者,注重消除者会采取Get瑟维斯方法的Type参数,钦定要创立的类,创制一个HomeController类的新实例。

3.笔者的依赖解决者诉求Ninject创造一个新的HomeController类,将Type对象传递给TryGet方法。

4.Ninject会检查HomeController的布局器,发掘它有一个宣称,重视了它应景绑定的IValueCalculator接口。

5.Ninject创设贰个LinqValueCalculator类的实例,并行使它创制三个HomeController类的心实例。

6.Ninject传递HomeController实例给自定义重视消除者,它会将他回去给MVC框架。MVC框架使用调整器的实例来为呼吁服务。

        小编深入分析得如此细,是因为在您首先次采用DI时,以为它稍稍奇怪奇怪让人费解。我那样做的三个低价,是前后相继中的任何调控器,都能声称三个依附,并且MVC框架会使用Ninject来解决它。

        最佳的片段是,当自家想要用别样实现替换LinqValueCalculator时,只供给改正正视解决者类。因为那是并世无两贰个地点,小编只得钦赐小编要使用IValueCalculator接口的兑现。

编辑:编程 本文来源:首先设计类来实现接口,本次将考察三类工具

关键词: