2.5.创建链式依赖

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

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

  1. public interface IDiscountHelper {
  2. decimal ApplyDiscount(decimal totalParam);
  3. }
  4. public class DefaultDiscountHelper : IDiscountHelper {
  5. public decimal ApplyDiscount(decimal totalParam) {
  6. return (totalParam - (10m / 100m * totalParam));
  7. }
  8. }

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

  1. public class LinqValueCalculator: IValueCalculator {
  2. private IDiscountHelper discounter;
  3. public LinqValueCalculator(IDiscountHelper discountParam) {
  4. discounter = discountParam;
  5. }
  6. public decimal ValueProducts(IEnumerable<Product> products) {
  7. return discounter.ApplyDiscount (products.Sum(p => p.Price));
  8. }
  9. }

新的构造器声明了一个IDiscountHelper接口的依赖。我指派构造器接收的实现对象给一个字段,并在ValueProducts方法中用它对产品对象的合计值应用折扣。

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

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

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

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

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

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

  1. public interface IDiscountHelper {
  2. decimal ApplyDiscount(decimal totalParam);
  3. }
  4. public class DefaultDiscountHelper : IDiscountHelper {
  5. public decimal DiscountSize { get; set; }
  6. public decimal ApplyDiscount(decimal totalParam) {
  7. return (totalParam - (DiscountSize / 100m * totalParam));
  8. }
  9. }

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

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

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

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

  1. public interface IDiscountHelper {
  2. decimal ApplyDiscount(decimal totalParam);
  3. }
  4. public class DefaultDiscountHelper : IDiscountHelper {
  5. public decimal discountSize;
  6. public DefaultDiscountHelper(decimal discountParam) {
  7. discountSize = discountParam;
  8. }
  9. public decimal ApplyDiscount(decimal totalParam) {
  10. return (totalParam - (discountSize / 100m * totalParam));
  11. }
  12. }

要使用Ninject绑定这个类,我在AddBindings方法的WithConstructorArgument方法指定构造器参数的值。

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

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

2.7.使用条件绑定

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

  1. public class FlexibleDiscountHelper : IDiscountHelper {
  2. public decimal ApplyDiscount(decimal totalParam) {
  3. decimal discount = totalParam > ? : ;
  4. return (totalParam - (discount / 100m * totalParam));
  5. }
  6. }

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

  1. private void AddBindings() {
  2. kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
  3. kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>
  4. ().WithConstructorArgument("discountParam", 50M);
  5. kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>()
  6. .WhenInjectedInto<LinqValueCalculator>();
  7. }

新绑定指定当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输出窗口。

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

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

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

  1. public HomeController(IValueCalculator calcParam, IValueCalculator calc2)
  2. {
  3. calc = calcParam;
  4. }

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

  1. Instance created
  2. Instance created

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

  1. using Ninject.Web.Common;
  2. namespace EssentialTools.Infrastructure {
  3. public class NinjectDependencyResolver : IDependencyResolver {
  4. ....
  5. private void AddBindings() {
  6. kernel.Bind<IValueCalculator>().To<LinqValueCalculator>
  7. ().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请求中,创建单一实例

Pro ASP.NET MVC 5 Framework.学习笔记.6.4.MVC的必备工具的更多相关文章

  1. Pro ASP.NET MVC 5 Framework.学习笔记.6.3.MVC的必备工具

    每个MVC程序员的军火库中,都有这三个工具:一个依赖注入(DI)容器,一个单元测试框架,一个模拟工具. 1.准备一个示例项目 创建一个ASP.NET MVC Web Application的Empty ...

  2. ASP.NET MVC Web API 学习笔记---第一个Web API程序

    http://www.cnblogs.com/qingyuan/archive/2012/10/12/2720824.html GetListAll /api/Contact GetListBySex ...

  3. ASP.NET Core Web开发学习笔记-1介绍篇

    ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...

  4. 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移

    不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...

  5. MVC缓存OutPutCache学习笔记 (二) 缓存及时化VaryByCustom

    <MVC缓存OutPutCache学习笔记 (一) 参数配置> 本篇来介绍如何使用 VaryByCustom参数来实现缓存的及时化.. 根据数据改变来及时使客户端缓存过期并更新.. 首先更 ...

  6. MVC缓存OutPutCache学习笔记 (一) 参数配置

    OutPutCache 参数详解 Duration : 缓存时间,以秒为单位,这个除非你的Location=None,可以不添加此属性,其余时候都是必须的. Location : 缓存放置的位置; 该 ...

  7. Entity Framework 学习笔记(2)

    上期回顾:Entity Framework 学习笔记(1) Entity Framework最主要的东西,就是自己创建的.继承于DbContext的类: /// <summary> /// ...

  8. Entity Framework学习笔记

    原文地址:http://www.cnblogs.com/frankofgdc/p/3600090.html Entity Framework学习笔记——错误汇总   之前的小项目做完了,到了总结经验和 ...

  9. thinkphp学习笔记7—多层MVC

    原文:thinkphp学习笔记7-多层MVC ThinkPHP支持多层设计. 1.模型层Model 使用多层目录结构和命名规范来设计多层的model,例如在项目设计中如果需要区分数据层,逻辑层,服务层 ...

随机推荐

  1. centos linux安全和调优 第四十一节课

    centos  linux安全和调优    第四十一节课 上半节课 Linux安全 下半节课 Linux调优 2015-07-01linux安全和调优 [复制链接]--http://www.apele ...

  2. XiaoShi657的留言板

    大家好,很荣幸能够借助此平台和大家分享.讨论编程技术! 有什么想对我说的请在这里留言吧

  3. 解决Regsvr32: DllRegisterServer entry point was not found

    原因: 虽然项目里面包含了DEF文件, 但是尼玛没有配置项目属性让链接器处理它啊! 解决方案: 项目属性->链接器->输入->模块定义文件->{输入文件名}

  4. electron Uncaught ReferenceError: jQuery is not defined

    用electron写桌面程序时 ui部分的html页面引入的js会用到jquery 用常规的方式引入是不行的,会抛出如题的异常 <script type="text/javascrip ...

  5. svn合并

    1.先去 aone里我的变更 里 重建 新分支 相当于重主干上拉代码下来2.然后再去 原来的分支里 swich切换到新分支3.在原来的分支里 merge 到新分支的url4.选择最早的 version ...

  6. ssh tunnel通道

    Secure SHell (SSH) 是一个通过网络登录其他计算机的程序,在远程服务器运行命令,和从一台机器移动文件到另一台.在不安全的网络中,它提供两台主机之间强大认证和安全加密的的通讯,被称为 S ...

  7. Codeforce Round #219 Div2

    妈蛋,C题又没搞出来! 看上去很简单的一题 到是这次的题目意思都比较容易懂,C没弄出来时,回去看了下A,以为来不及了,没想到这次的手速还是可以的7分钟搞出来了,因为太简单- -! A:大于两倍的不行- ...

  8. 20145207 《Java程序设计》第5周学习总结

    前言:先聊两句,上午电路实习,刚开始没多久就让电烙铁烫了,倒霉催的~晚上来这里接着弄代码,透心凉心飞扬~ 教材学习内容总结 一.异常处理 1.语法与继承结构 使用try.catch: Java中所有错 ...

  9. [摘录] 关于 java 并发包

    1.http://www.raychase.net/698 Java多线程发展简史

  10. Linux 配置双机SSH信任

    一.实现原理 使用一种被称为"公私钥"认证的方式来进行ssh登录."公私钥"认证方式简单的解释是: 首先在客户端上创建一对公私钥(公钥文件:~/.ssh/id_ ...