zoukankan      html  css  js  c++  java
  • Pro ASP.NET MVC 5 Framework.学习笔记.6.4.MVC的必备工具

    2.5.创建链式依赖

            当你请求Ninject创建一个类型,它检查该类型的依赖是否声明。它也会检查该依赖是否依赖其他类型。如果这里有附加依赖,Ninject自动解决他们,并创建请求的所有类的实例。正是由于这样的链式依赖,它最后创建了你请求的类型的实例。

            要展示这个特性,我已经添加一个叫做DisCount的类,到Models文件夹,用它来定义一个新的接口,和该接口的一个实现。

    public interface IDiscountHelper {
        decimal ApplyDiscount(decimal totalParam);
    }
    public class DefaultDiscountHelper : IDiscountHelper {
        public decimal ApplyDiscount(decimal totalParam) {
            return (totalParam - (10m / 100m * totalParam));
        }
    }

            IDiscountHelper定义了一个ApplyDiscount方法,它对一个decimal值应用折扣。DefaultDiscounterHelper类实现了IDiscountHelper接口,应用了一个固定10%的折扣。我要修改LinqValueCalculator类,让它执行计算时,使用IDiscountHelper接口。

    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方法中用它对产品对象的合计值应用折扣。

            我用NinjectDependencyResolver类中的Ninject kernel绑定IDiscountHelper接口到实现类。

    private void AddBindings() {
        kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
        kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
    }

            我已经创建了一个依赖链。我的Home控制器依赖于IValueCalculator接口,我已经告诉Ninject用LinqValueCalculator类来解决。而LinqValueCalculator类依赖于IDiscountHelper接口,我已经告诉Ninject使用DefaultDiscountHelper类来解决。

            Ninject无缝隙地解决链式依赖。

    2.6.指定属性和构造器参数值

            在绑定接口到它的实现时,我能通过提供详细的值给属性,来配置Ninject创建的对象。要演示这个特性,我要创建修订DefaultDiscountHelper类,让他定义一个DiscountSize属性,用它来计算折扣额度。

    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));
        }
    }

            当我告诉Ninject要用接口的哪个实现时,可以使用WithPropertyValue方法,为DefaultDiscountHelper类的DiscountSize属性设置值。可以看到,我提供将属性的名字,作为字符串值设置。

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

            我不需要改变任何其他绑定,也不需要改变我使用Get方法获得ShoppingCart类的实例的方式。

            如果你有多个属性值要设置,可以使用链式调用WithPropertyValue方法。我可以用构造器参数来做同样的事情。折扣的额度作为DefaultDiscountHelper类的构造器参数。

    public interface IDiscountHelper {
        decimal ApplyDiscount(decimal totalParam);
    }
    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);
    }

            再一次,链式调用这些方法,提供多个值。在改变方法名称的同时,也改变了传递的参数。

    2.7.使用条件绑定

            Ninject提供一些条件绑定方法,允许我指定kernel应该用哪个类来响应特定接口的请求。要演示这点,我在Models文件夹下添加了一个FlexibleDiscountHelper类。

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

            FlexibleDiscountHelper类基于总的数量级,应用不同的折扣。现在我需要选择IDiscountHelper接口的实现类,我可以修改NinjectDependencyResolver的AddBindings方法,来告诉Ninject。

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

            新绑定指定当Ninject kernel创建一个LinqValueCalculator对象时,应该使用FlexibleDiscountHelper类作为IDiscountHelper接口的实现。注意,我已经有原始绑定到IDiscountHelper。Ninject试着找到最匹配的。Ninject支持一组不同条件绑定方法,最有用的是下面的:

    Method Effect
    When(条件) 当条件——lambda表达式等于true时
    WhenClassHas<T>() 当要被注入的类含有一个T类型的属性时
    WhenInjectedInto<T>() 当要被注入的类是T类型时

    2.8.设置对象目标

            Ninject最后一个特性,帮助制作对象的生命周期。默认地,Ninject在每个对象需要解决每个依赖每次你请求一个对象时,它都会创建一个新的实例。

            要演示发生了什么,我已经修改了LinqValueCalculator类的构造器,当一个新的实例被创建时,让它输出一个消息到VS输出窗口。

    public class LinqValueCalculator : IValueCalculator {
        private IDiscountHelper discounter;
        private static int counter = 0;
        public LinqValueCalculator(IDiscountHelper discountParam) {
            discounter = discountParam;
            System.Diagnostics.Debug.WriteLine(
    string.Format("Instance {0} created", ++counter));
        }
        public decimal ValueProducts(IEnumerable<Product> products) {
            return discounter.ApplyDiscount(products.Sum(p => p.Price));
        }
    }

            System.Diagnostics.Debug类包含一组方法,可以用来输出调试消息。在查看代码如何工作时,我发现他们很有用。

            Home控制器添加了两个IValueCalculator接口的实现。

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

            我没有执行任何游泳的任务,只是请求两个接口的实现。如果运行示例,会看到Ninject创建了两个LinqValueCalculator类的实例。

    Instance 1 created
    Instance 2 created

            LinqValueCalculator可以被实例化,但是不是所有的类都能。对于一些类,你希望在整个应用中共享单一实例。另外一些,你希望为每个ASP.NET平台服务的HTTP请求,都创建一个新的实例。Ninject允许你使用目标的特性,控制对象的生命周期,你会看到对于MVC框架这是多么有用的目标:在NinjectDependencyResolver中请求目标到LinqValueCalculator类。

    using Ninject.Web.Common;
    namespace EssentialTools.Infrastructure {
    public class NinjectDependencyResolver : IDependencyResolver {
    ....
    private void AddBindings() {
    kernel.Bind<IValueCalculator>().To<LinqValueCalculator>
    ().InRequestScope();

            InRequestScope扩展方法,在Ninject.Web.Common命名空间里。它告诉Ninject,应该为每个ASP.NET服务的HTTP请求,只创建一个LinqValueCalculator类的实例。每个请求会得到它自己分离的对象,但在相同的请求里的多个依赖,会用类的相同实例解决。你可以看这个改变的影响,通过启动程序,查看VS输出窗口。它会显示Ninject只创建了一个LinqValueCalculator类的实例。如果你刷新浏览器,而不是重启程序,你会看到Ninject创建了第二个对象。Ninject提供一列不同的对象目标,最有用的是:

    Name Effect
    InTransientScope() 和没有指定目标一样,为每个依赖创建一个新的对象
    InSingletonScope()ToConstant(object) 在整个应用中共享一个单一实例。如果使用InSingletoScope,Ninject会创建实例。如果用ToConstant方法,并提供这个实例,也会在整个程序中共享单一实例。。
    InThreadScope() 在单一线程中,创建一个单一实例
    InRequestScope() 在单一HTTP请求中,创建单一实例
  • 相关阅读:
    Hihocoder 1275 扫地机器人 计算几何
    CodeForces 771C Bear and Tree Jumps 树形DP
    CodeForces 778D Parquet Re-laying 构造
    CodeForces 785E Anton and Permutation 分块
    CodeForces 785D Anton and School
    CodeForces 785C Anton and Fairy Tale 二分
    Hexo Next 接入 google AdSense 广告
    如何统计 Hexo 网站的访问地区和IP
    Design and Implementation of Global Path Planning System for Unmanned Surface Vehicle among Multiple Task Points
    通过ODBC接口访问人大金仓数据库
  • 原文地址:https://www.cnblogs.com/msdynax/p/3672067.html
Copyright © 2011-2022 走看看