一,创建依赖链(Chains of Dependency)

当我们向Ninject请求创建一个类型时,Ninject会去检查该类型和其他类型之间的耦合关系。如果有额外的依赖,Ninject也会解析它们并创建我们需要的所有类的实例。为了进一步说明,我们创建一个新的接口和一个实现该接口的类。请注意我们的例子是跟前面的笔记衔接的,所以如果你打算跟着一起操作的话,最好能够去看看前面的笔记。

创建一个IDiscountHelper如下所示:

public interface IDiscountHelper
{
//Product打折应用
decimal ApplyDiscount(decimal totalParam);
}

  

创建一个实现IDiscountHelper的类如下所示:

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

  

下面在LinqValueCalculator.cs添加依赖(这个类是前面的笔记里面的)

public class LinqValueCalculator : IValueCalculator
{
private IDiscountHelper discounter; public LinqValueCalculator(IDiscountHelper discountParam)
{
discounter = discountParam;
} public decimal ValueProducts(params Product[] products)
{
return discounter.ApplyDiscount(products.Sum(p => p.Price));
}
}

  

同样是通过Constructor Injection的方式

下面采取同样的方式将接口绑定到实现,如下所示:

static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//绑定接口到其对应的实现
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>(); //获取接口实现
IValueCalculator calcuImpl = ninjectKernel.Get<IValueCalculator>(); ShoppingCart cart = new ShoppingCart(calcuImpl); //执行
Console.WriteLine("Tatol:{0:c}", cart.CalculateStockValue()); }

  

我们使用Ninject将两个接口分别绑定到对应的实现类,我们不必改变实现IValueCalculator类的任何代码。Ninject知道当我们请求IValueCalculator的类型时就实例化LinqValueCalculator对象返回给我们。它会去检查这个类,并发现LinqValueCalculator依赖另一个接口,并且这个接口是它能解析的,Ninject创建一个DefaultDiscountHelper的实例注入LinqValueCalculator类的构造器,并返回IValueCalculator类型的对象。Ninject会只用这种方式检查每一个要实例化的类的依赖,不管涉及的依赖链有多复杂,多冗长。
二,指定属性和参数值

1.我们可以提供一些属性的具体值或者详细信息给Ninject,当我们要绑定接口到实现的时候。上面的例子里面我的打折9折,而且是写死的。现在我们对其进行修改,如下所示:

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

  

这里我们定义了一个属性来表示具体的折扣。当我们再来绑定这个具体的类时,我们可以进行下面的操作.如下所示:

static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//绑定接口到其对应的实现
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50m);//打5折哈 //获取接口实现
IValueCalculator calcuImpl = ninjectKernel.Get<IValueCalculator>(); ShoppingCart cart = new ShoppingCart(calcuImpl); //执行
Console.WriteLine("Tatol:{0:c}", cart.CalculateStockValue()); }

  

当然如果你有多个属性,可以接用"."链式的添加。

2.上面是通过定义一个属性来实现折扣,我们也可以通过定义在构造器里的参数实现,

如下所示:

public class DefaultDiscountHelper : IDiscountHelper
{
private decimal discountRate; public DefaultDiscountHelper(decimal discountParam)
{
discountRate = discountParam;
} public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (discountRate/ 100m * totalParam));
}
}

  

这个时候我们绑定的时候是这样的:ninjectKernel.Bind<IDiscountHelper>().To< DefaultDiscountHelper>().WithConstructorArgument("discountParam", 50M); 同样我们如果有多个构造器参数,也采用"."的方式链式添加。
3.使用Self-Binding

一个非常有用的功能:Self-Binding(自我绑定)能够完全将Ninject整合到我们的代码里面,也就是来自Ninject内核被请求的类的地方。这可能看起来有点奇怪,这也意味着我们不用手动的执行DI的初始化。向下面这个地方:

IValueCalculator calcImpl = ninjectKernel.Get<IValueCalculator>();  ShoppingCart cart = new ShoppingCart(calcImpl); 

我们可以简单的请求一个ShoppingCart的实例并让Ninject挑选出对IValueCalculator依赖的类。

通过这种方式:ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); Self-Binding到一个具体的类,通过这种方式:ninjectKernel.Bind<ShoppingCart>().ToSelf().WithParameter(Parameter);具体如下所示:

static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//绑定接口到其对应的实现
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50m); //获取接口实现
//IValueCalculator calcuImpl = ninjectKernel.Get<IValueCalculator>(); //ShoppingCart cart = new ShoppingCart(calcuImpl); ninjectKernel.Bind<ShoppingCart>().ToSelf();//如果注释掉这行也不影响程序运行,我还不知道原因,有路过的大牛请指导下。 ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); //执行
Console.WriteLine("Tatol:{0:c}", cart.CalculateStockValue()); }

  

4.绑定到派生类型(Binding to a Derived Type)

尽管我们前面一直关注的是绑定接口(因为接口跟MVC里面的相关性更强),我们也可以使用Ninject绑定具体的类,Self-Binding就是这样做的。我们也可以使用Ninject绑定一个具体的类到它的派生类。我想这里也好理解,因为我们绑定接口到实现它的类--类继承了该接口,这里是类继承了类罢了。

下面我们修改ShoppingCart类,使其能够支持简单的派生l类--LimitShoppingCart.提供一个限制价格上限的属性ItemLimit。修改后的ShoppingCart类如下所示:

public class ShoppingCart
{
protected IValueCalculator calculator;
protected Product[] products;
public ShoppingCart(IValueCalculator calcParam)
{
calculator = calcParam;
products = new[] {
new Product() { Name = "Kayak", Price = 275M},
new Product() { Name = "Lifejacket", Price = 48.95M},
new Product() { Name = "Soccer ball", Price = 19.50M},
new Product() { Name = "Stadium", Price = 79500M}
};
}
public virtual decimal CalculateStockValue() //定义为虚方法,在派生类里面重写该方法
{
decimal totalValue = calculator.ValueProducts(products);
return totalValue;
}
}

  

派生类LimitShoppingCart如下所示:

public class LimitShoppingCart : ShoppingCart
{ public LimitShoppingCart(IValueCalculator calcParam)
: base(calcParam)
{
//调用基类的构造器,为的是在初始话LimitShoppingCart时首先调用ShoppingCart的构造器
//因为我们要使用calculator
} public override decimal CalculateStockValue()
{
//这里过滤掉哪些价格超过了上限的Product,任何再求和
var filteredProducts = products.Where(e => e.Price < ItemLimit);
return calculator.ValueProducts(filteredProducts.ToArray());
} public decimal ItemLimit { get; set; }
}

  

  

下面我们绑定ShoppingCart到它的派生类LimitShoppingCart,如下所示:

static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//绑定接口到其对应的实现
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50m); //获取接口实现
//IValueCalculator calcuImpl = ninjectKernel.Get<IValueCalculator>(); //ShoppingCart cart = new ShoppingCart(calcuImpl); //ninjectKernel.Bind<ShoppingCart>().ToSelf(); //ShoppingCart cart = ninjectKernel.Get<ShoppingCart>();
ninjectKernel.Bind<ShoppingCart>().To<LimitShoppingCart>().WithPropertyValue("ItemLimit", 200M);
ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); //执行
Console.WriteLine("Tatol:{0:c}", cart.CalculateStockValue()); }

  

5.使用条件绑定(Conditional Binding)

有时对同一个接口会有多重实现或者是对同一个类有多个派生,这时可以指定不同的条件来说明哪一个应该被使用。下面通过具体的实例说明: 创建一个新的IValueCalculator的接口实现IterativeValueCalculator.cs如下所示:

public class IterativeValueCalculator : IValueCalculator
{
public decimal ValueProducts(params Product[] products)
{
decimal totalValue = 0;
foreach (Product p in products)
{
totalValue += p.Price;
}
return totalValue;
}
}

  

  

现在我们有了对IValueCalculator的两个实现了,可以通过Ninject设置条件来指定哪个显示被使用。如下所示:

static void Main(string[] args)
{
IKernel ninjectKernel = new StandardKernel();
//绑定接口到其对应的实现
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
//ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50m); //获取接口实现
//IValueCalculator calcuImpl = ninjectKernel.Get<IValueCalculator>();
//ShoppingCart cart = new ShoppingCart(calcuImpl); //Self-Binding
//ninjectKernel.Bind<ShoppingCart>().ToSelf();
//ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); //Bind to Derived class
//ninjectKernel.Bind<ShoppingCart>().To<LimitShoppingCart>().WithPropertyValue("ItemLimit", 200M);
//ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); //Conditional Binding
ninjectKernel.Bind<IValueCalculator>().To<IterativeValueCalculator>().WhenInjectedInto<LimitShoppingCart>();
ninjectKernel.Bind<ShoppingCart>().To<LimitShoppingCart>().WithPropertyValue("ItemLimit", 200M);
ShoppingCart cart = ninjectKernel.Get<ShoppingCart>(); //执行
Console.WriteLine("Tatol:{0:c}", cart.CalculateStockValue()); }

  

我们可以通过断点调试运行看看是否进到了IterativeValueCalculator里面,从而判断我们设置的条件是否起到了作用。我试过了,不管你信不信,反正我是信了!嘿嘿!当然如果我们的条件没有一个合适也没有关系,Ninject会寻找一个对该类或接口的默认的绑定,以至于Ninject会有一个返回的结果。这个有点类似我们使用Switch时一般提倡加上Default也是这个道理。

下图是关于Ninject条件绑定的方法,如下所示:

另,我想说IoC容器有几种这里使用是其中的一种,大家可以自由选择一个IoC容器

6.在ASP.NET MVC中应用Ninject

之前的比较使用控制台应用程序为例介绍了Ninject的核心功能,但是要将Ninject整合到ASP.NET MVC中并不是太容易。首先我们需要创建一个类继承自 System.Web.Mvc.DefaultControllerFactory,这个类是MVC Framework默认用来创建controller实例的类(当然在书的后面的章节会介绍如何创建自定义的实现来替代default controller factory).这里我们的实现如下所示:

public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel; public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
} protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
} private void AddBindings()
{
ninjectKernel.Bind<IProductRepository>().To<FakeProductRepository>();
}
}

  

这个类创建了Ninject的核心,通过GetControllerInstance()方法为controller classes的请求服务,这个方法在需要一个controller对象的时候被MVC框架调用。我们不必使用Ninject显示的绑定controller classes。由于controllers classes继承了System.Web.Mvc.Controller,我们可以依靠默认的self-binding。AddBindings()方法允许我们绑定Repositories和其他需要保持松耦合的组件。我们也可以使用这个方法绑定需要额外的构造器参数或属性参数的controller classes。

一旦我们创建了这个类,我们需要在MVC Framework的Global.asax里面注册。注册的方法如下:

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
}

  

现在MVC Framework就会使用我们的NinjectControllerFactory来获取controller classes的实例,并且Ninject会自动处理controller 对象的DI(依赖注入)。后面章节的比较会有关于这部分的例子。这里你可以先了解下大概的原理。可能到这里的时候,我们会觉得在Ninject上面花费的很多功夫,似乎跟MVC的学习不是很相关。但是我们DI的深刻的理解能够帮助我们开发和测试更加简单,容易。

转从:http://www.cnblogs.com/mszhangxuefei/archive/2011/12/10/mvcnotes_9.html

轻量级IOC框架:Ninject (下)的更多相关文章

  1. 轻量级IoC框架Ninject.NET搭建

    说在之前的话 IOC的概念相信大家比较熟悉了,习惯性称之为依赖注入或控制反转,园子里对基于MVC平台IOC设计模式已经相当多了,但大家都只知道应该怎么应用一个IOC模式,比如Ninject, Unit ...

  2. 轻量级IOC框架:Ninject

    Ninject 学习杂记 - liucy 时间2014-03-08 00:26:00 博客园-所有随笔区原文  http://www.cnblogs.com/liucy1898/p/3587455.h ...

  3. IOC框架Ninject实践总结

    原文地址:http://www.cnblogs.com/jeffwongishandsome/archive/2012/04/15/2450462.html IOC框架Ninject实践总结 一.控制 ...

  4. 轻量级IOC框架Guice

    java轻量级IOC框架Guice Guice是由Google大牛Bob lee开发的一款绝对轻量级的java IoC容器.其优势在于: 速度快,号称比spring快100倍. 无外部配置(如需要使用 ...

  5. 轻量级IOC框架:Ninject (上)

    前言 前段时间看Mvc最佳实践时,认识了一个轻量级的IOC框架:Ninject.通过google搜索发现它是一个开源项目,最新源代码地址是:http://github.com/enkari/ninje ...

  6. java轻量级IOC框架Guice(转)

    出处:http://www.cnblogs.com/whitewolf/p/4185908.html Guice是由Google大牛Bob lee开发的一款绝对轻量级的java IoC容器.其优势在于 ...

  7. java轻量级IOC框架Guice

    Google-Guice入门介绍(较为清晰的说明了流程):http://blog.csdn.net/derekjiang/article/details/7231490 使用Guice,需要添加第三方 ...

  8. 轻量级IOC框架SwiftSuspenders

    该框架的1.6版本位于https://github.com/tschneidereit/SwiftSuspenders/blob/the-past/,现在已经出了重新架构的2.0版本,所以我决定先研究 ...

  9. 轻量级IOC容器:Ninject

    Ninject是一个快如闪电.超轻量级的基于.Net平台的依赖注入框架.它能够帮助你把应用程序分离成一个个松耦合.高内聚的模块,然后用一种灵活的方式组装起来.通过使用Ninject配套你的软件架构,那 ...

随机推荐

  1. Java插件开发-取插件下的某个文件

    //找到插件所在处 Bundle bundle = Activator.getDefault().getBundle(); //根据插件转义成URL路径 URL url = FileLocator.t ...

  2. jsp、js分页功能的简单总结

    一.概述 首先,我们要明确为何需要分页技术,主要原因有以下: 1.分页可以提高客户体验度,适当地选择合适的数据条数,让页面显得更有条理,使得用户体验感良好,避免过多数据的冗余. 2.提高性能的需要.分 ...

  3. 用sessionStorage实现页面之间的数据传输

    1.sessionStorage主要含几种方法: //页面A:存放一个简单的字符串 sessionStorage.obj = '123'; //页面B:取到给obj var str = session ...

  4. Unreal Engine 4官网教程

    编辑器纵览 https://www.unrealengine.com/zh-CN/blog/editor-overview 虚幻编辑器UI布局概述 https://www.unrealengine.c ...

  5. 【VerySky原创】 ME9F

    [VerySky原创] V_EKKONA - Generierte Tabelle zu einem View V_EKKONA-PFLD4 字段 SE71查看 至于图片:在表STXBITMAPS中 ...

  6. webRTC-实时流媒体的福音

    WebRTC是一项在浏览器内部进行实时视频和音频通信的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术.[1] WebRTC实现了基于网页的视频会议 ...

  7. android 开发 简单的页面布局

    package com.example.test; import android.app.Activity; import android.os.Bundle; import android.view ...

  8. javaweb 学习总结

    http://www.cnblogs.com/xdp-gacl/category/574705.html 这个总结很好,以前看书没搞懂的,这里基本上都清楚了,赞一个,推荐. Servlet与普通Jav ...

  9. 用 Mahout 和 Elasticsearch 实现推荐系统

    原文地址 本文内容 软件 步骤 控制相关性 总结 参考资料 本文介绍如何用带 Apache Mahout 的 MapR Sandbox for Hadoop 和 Elasticsearch 搭建推荐引 ...

  10. 关于NMF(Non-negative Matrix Factorization )

    著名的科学杂志<Nature>于1999年刊登了两位科学家D.D.Lee和H.S.Seung对数学中非负矩阵研究的突出成果.该文提出了一种新的矩阵分解思想――非负矩阵分解(Non-nega ...