https://blog.csdn.net/qq_21419015/article/details/80474956
这里主要介绍三类工具之一的 依赖项注入(DI)容器,其他两类 单元测试框架和模仿工具以后介绍。
1、准备示例项目
从创建一个简单的示例开始,名称为"EssentialTools" ,使用MVC空模板,如下所示:
创建模型类
在 Models 文件夹中添加一个名为 Products.cs 的类,添加内容如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
定义产品类
namespace EssentialTools.Models
{
public class Product
{
public int ProductId { get; set; }
public string Name { set; get; }
public string Description { get; set; }
public decimal Price { set; get; }
public string Category { get; set; }
}
}
定义计算类,参数是产品类可枚举对象
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public class LinqValueCalculator
{
public decimal ValueProducts(IEnumerable<Product> products)
{
return products.Sum(p => p.Price);
}
}
}
定义模型类ShoppingCart,内含计算类对象,产品对象枚举
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public class ShoppingCart
{
private LinqValueCalculator calc;
public ShoppingCart(LinqValueCalculator calcParam)
{
calc = calcParam;
}
public IEnumerable<Product> Products{ get; set; }
public decimal CalculateProductToal()
{
return calc.ValueProducts(Products) ;
}
}
}
添加控制器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EssentialTools.Models;
namespace EssentialTools.Controllers
{
public class HomeController : Controller
{
// GET: Home
private Product[] products = 产品类对象
{
new Product {Name = "Kayak",Description = "Watersports",Category = "Watersport",Price = 122M },
new Product {Name = "Lifejacket",Description = "Watersports",Category = "Watersports",Price = 162M },
new Product {Name = "Soccer ball",Description = "Soccer",Category = "Soccer",Price = 172.25M },
new Product {Name = "Corner flag",Description = "Soccer",Category = "Soccer",Price = 82.15M }
};
public ActionResult Index()
{
LinqValueCalculator lvc = new LinqValueCalculator(); 计算类对象
ShoppingCart sc = new ShoppingCart(lvc){ Products = products }; 模型类对象
decimal totalValue = sc.CalculateProductToal();
return View(totalValue);
}
}
}
添加视图
最后给项目添加视图,选中Index 右键添加视图,设置内容如下所示:
@model decimal
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
总价格为:$@Model
</div>
</body>
</html>
这个视图使用@Model 表达式显示了从动作方法传递过来的 decimal 值。如果启动项目,会看到LinqValueCalculator 类计算的总值。
右键视图,在浏览器中查看:
2、使用Ninject
在 ASP.NET + MVC5 入门完整教程三 (下) ---MVC 松耦合 中介绍了DI,这里主要介绍如何使用Ninject。
理解问题
ShoppingCart 类与 LinqValueCalculator 类是紧耦合的,而HomeController 类与 ShoppingCart 类和 LinqValueCalculator 类都是紧耦合的。这意味着替换 LinqValueCalculator 类,就必须在与他有紧耦合关系的类中找出对他的引用并进行修改。如果项目比较复杂,这就是个麻烦事。
定义接口
通过使用C#接口,从计算器实现中抽象出其功能定义。在“Models”文件夹下添加一个“IValueCalculator.cs”接口,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public interface IValueCalculator
{
decimal ValueProducts(IEnumerable<Product> products);
}
}
定义计算类,派生于接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public class LinqValueCalculator : IValueCalculator
{
public decimal ValueProducts(IEnumerable<Product> products) 接口派生类中定义方法
{
return products.Sum(p => p.Price);
}
}
}
定义模型类ShoppingCart,内含接口对象,产品对象枚举
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public class ShoppingCart
{
//private LinqValueCalculator calc;
//public ShoppingCart(LinqValueCalculator calcParam)
//{
// calc = calcParam;
//}
private IValueCalculator calc;
public ShoppingCart(IValueCalculator calcParam) 类构造函数参数是接口
{
calc = calcParam;
}
public IEnumerable<Product> Products{ get; set; }
public decimal CalculateProductToal()
{
return calc.ValueProducts(Products) ; 调用接口函数
}
}
}
上述过程ShoppingCart构造函数只需要 ICalculator 接口对象,解除了 与 ValueCalculator 之间的耦合,ShoppingCart类与 IValuecalculator 的实现类之间不再有直接联系, 但是C#要求在接口实例化时要指定其实现类,这很好理解,因为它需要知道程序想用的是哪一个实现类。这意味着,Home控制器在创建 LinqvalueCalculator 对象时仍有问题,如下所示:
public ActionResult Index()
{
//LinqValueCalculator lvc = new LinqValueCalculator();
IValueCalculator lvc = new LinqValueCalculator();//可通过引入 Ninject 而简化 接口实例化时要指定其实现类,
ShoppingCart sc = new ShoppingCart(lvc) { Products = products };
decimal totalValue = sc.CalculateProductToal();
return View(totalValue);
}
使用 Ninject的目的就是要去掉 Home 控制器与总价计算器 LinqValueCalculator之间的耦合。
将 Ninject 添加到 Visual Studio项目
将Ninject添加到MvC项目最简单的方式,是使用 Visual studio对 NuGet的集成支持,这使 Visual Studio 易于安装各种各样的包,并保持这些包为最新。在 Visual studio中选择“Tool(工具)”→“ Library Package Manager(库包管理器)”→“ Package Manager Console(包管理器控制台)”,如下所示:
安装完成上图三个插件,都更新到最新版本,保证前面都是绿色勾,及说明版本已经匹配,这时候在App_Start 文件夹下会出现 Ninject.Web.Common 文件。这说明Ninject 已经成功引入项目工程,可以使用了。打开 Ninject.Web.Common 文件,有两个错误需要修改,其实是少了一个命名空间引用,加入 using Ninject.Web.Common.WebHost 即可。
Ninject 初步
为了 使用 Ninject 的基本功能,要做 3 个 阶段工作。在 Home 控制器文件中做如下修改:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EssentialTools.Models;
using Ninject;
namespace EssentialTools.Controllers
{
public class HomeController : Controller
{
// GET: Home
private Product[] products =
{
new Product {Name = "Kayak",Description = "Watersports",Category = "Watersport",Price = 122M },
new Product {Name = "Lifejacket",Description = "Watersports",Category = "Watersports",Price = 162M },
new Product {Name = "Soccer ball",Description = "Soccer",Category = "Soccer",Price = 172.25M },
new Product {Name = "Corner flag",Description = "Soccer",Category = "Soccer",Price = 82.15M }
};
public ActionResult Index()
{
//LinqValueCalculator lvc = new LinqValueCalculator();
//IValueCalculator lvc = new LinqValueCalculator();
//创建一个Ninject内核对象
IKernel ninjectKernel = new StandardKernel();
//将想使用的类型和他的接口进行绑定,告诉Ninject,当接收到一个实现IValueCalculater的请求的时候,创建并返回LinqValueCalculator这个类,上面的两个关键字Bind,To可以帮助我们理解他的意思
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//用Ninject的Get方法去获取IValueCalculator接口的实现
IValueCalculator lvc = ninjectKernel.Get<IValueCalculator>();
//创建ShoppingCart实例并注入依赖(products )
ShoppingCart sc = new ShoppingCart(lvc) { Products = products };
decimal totalValue = sc.CalculateProductToal();
return View(totalValue);
}
}
}
建立 MVC 的依赖项注入
创建依赖项解析器
要做的第一个修改是创建一个自定义的依赖项解析器。MVC框架需要使用依赖项解析器来创建类的实例,以便对请求进行服务。通过创建自定义解析器,便能保证MVC框架在任何时候都能使用 Ninject创建一个对象—包括控制器实例。为了创建这个解析器,先创建了一个新的文件夹,名称为 Infrastructure,用于放置MVC应用程序中不适合放在其他文件夹的类。在该文件夹中添加一个新的类文件,名称为 NinjectDependencyResolver.cs,文件内容如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EssentialTools.Models;
using System.Web.Mvc;
using Ninject;
namespace EssentialTools.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kekrnelParam)
{
kernel = kekrnelParam;
AddBindings();
}
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
}
}
直接写 :IDependencyResolver 会出现错误,此时选中 IDependencyResolver 如下所示:
自动生成 GetService 和 GetServices 方法,在按照上面代码修改GetService 和 GetServices 方法,前提是已经引入下面的命名空间。
using Ninject;
using System.Web.Mvc;
NinjectDependencyResolver 类实现了 IDependencyResolver接口,它属于 System.Web.MVC 命名空间,也由MVC框架用于获取其所需的对象。MVC框架在需要类实例以便对一个传入的请求进行服务时,会调用 Getservice或 Getservices方法。依赖项解析器要做的工作便是创建这一实例——这是一项要通过调用 Ninject的 TryGet 和 GetAll 方法来完成的任务。TryGet 方法的工作方式类似于前面所用的Get方法,但当没有合适的绑定时,它会返回 null,而不是抛出一个异常。GetAll 方法支持对单一类型的多个绑定,当有多个不同的服务提供器可用时,可以使用它。上述依赖项解析器类也是建立 Ninject 绑定的地方。在 AddBindings 方法中,用 Bind 和To 方法配置了 IValueCalculator 接口和 LinqValueCalculator 类之间的关系。
注册依赖项解析器
仅仅简单地创建一个 IDependencyResolver 接口的实现是不够的,还必须告诉 MVC 框架需要使用它。笔者用 NuGet添加的 Ninject 包在 App_Start 文件夹中创建了一个名称为 Ninject.Web.common.cs 的文件,它定义了应用程序启动时会自动调用的一些方法,目的是将它们集成到 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)); // 创建一个NinjectDependencyResolver 类的实例,并且注册为 MVC 框架的解析器
}
重构 Home 控制器
最后一步就是重构 Home 控制器,以便利用前面所建立的功能,如下加粗所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using EssentialTools.Models;
using Ninject;
namespace EssentialTools.Controllers
{
public class HomeController : Controller
{
// GET: Home
private IValueCalculator lvc;
private Product[] products =
{
new Product {Name = "Kayak",Description = "Watersports",Category = "Watersport",Price = 122M },
new Product {Name = "Lifejacket",Description = "Watersports",Category = "Watersports",Price = 162M },
new Product {Name = "Soccer ball",Description = "Soccer",Category = "Soccer",Price = 172.25M },
new Product {Name = "Corner flag",Description = "Soccer",Category = "Soccer",Price = 82.15M }
};
public HomeController(IValueCalculator calcParam)
{
lvc = calcParam;
}
public ActionResult Index()
{
//LinqValueCalculator lvc = new LinqValueCalculator();
//IValueCalculator lvc = new LinqValueCalculator();
//IKernel ninjectKernel = new StandardKernel();
//ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
//IValueCalculator lvc = ninjectKernel.Get<IValueCalculator>(); //三步配置
ShoppingCart sc = new ShoppingCart(lvc) { Products = products };
decimal totalValue = sc.CalculateProductToal();
return View(totalValue);
}
}
}
所做的主要修改是添加了一个类构造器,用于接收 IValueCalculator 接口的实现,即修改 HomeController 类,使其声明一个依赖项。Ninject会在创建该控制器实例时,使用在HomeController中建立起来的配置,为该控制器创建一个实现 IValueCalculator 接口的对象所做的另一个修改是从控制器中删除了任何关于 Ninject 或 LinqValueCalculator 类的代码。最终,打破了 Homecontroller 与 LinqValueCalculator 类之间紧耦合。
右键 Views 视图下的 Index.cshtml ,在浏览器中查看,可以看到如下所示效果:
以上创建的是一个构造器注入示例,这是依赖项注入的一种形式。
创建依赖项链
当要求 Ninject 创建一个类型时,它会检查该类型所声明的依赖项。它也会考查这些依赖项,看其是否依赖于其他类型—换句话说,它们是否还声明了自己的依赖项。如果有额外的依赖项 Ninject 会自动地解析这些依赖项,并创建所需要的所有类的实例,以这种方式处理依赖项链,最终更能够创建所需类型的实例(本段描述了 Inject处理依赖项链的工作方式)。为了演示这一特性,在项目的 Models文件夹中添加了一个名称为 Discount.cs文件。并用它定义了一个新的接口及其实现类,如下所示
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public interface IDiscountHelper
{
decimal ApplyDiscount(decimal totalParam);
}
public class DefaultDiscountHelper : IDiscountHelper
{
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (10M / 100M * totalParam));
}
}
}
IDiscountHelper 定义了ApplyDiscount 方法,他将一个折扣运用于一个十进制的值。DefaultDiscountHelper 类实现了IDiscountHelper 接口,并运用固定的 10% 折扣,这里修改 LinqValueCalculator ,以使他执行计算时使用 IDiscountHelper 接口,如下粗体所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
public class LinqValueCalculator : IValueCalculator
{
private IDiscountHelper discounter;
private static int counter = 0;
public LinqValueCalculator(IDiscountHelper discountParam)
{
discounter = discountParam;
}
public decimal ValueProducts(IEnumerable<Product> products)
{
return discounter.ApplyDiscount(products.Sum(p => p.Price));
}
}
}
新的构造器声明了一个 IDiscounthelper 接口的依赖项。这里将构造器所接收的实现对象赋给了一个字段,并在 ValueProducts 方法中使用了它,以便将一个折扣运用于 Product 对象的累计值如同对 IValueCalculator 所做的那样,在 NinjectDependencyResolver 类中用 Ninject 内核将 IDiscountHelper 接口与其实现类进行绑定,如下粗体所示。
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
}
上述这一做法已经创建了一个依赖项链。此时 Home 控制器依赖于 IValueCalculator 接口,这里已经告诉 Ninject 用 LinqValueCalculator 类对该接口进行解析。LinqValueCalculator 类又依赖于 IDiscountHelper 接口,这里又告诉 Ninject 用 DefaultdiscountHelper 类对其进行解析。Ninject 能够平滑地解析这种依赖项链,创建所需的对象为每一个依赖项进行解析,于是最终能创建一个 HomeController 类的实例,从而对一个HTTP请求进行服务。
指定属性和构造器参数值
在将接口与其实现进行绑定时,可以为属性提供一些值方面的细节,以便对 Inject创建的对象进行配置。为了演示这一特性,这里我修订了 DefaultDiscountHelper 类,以使它定义一个 DiscountSize 属性,将其用于计算折扣量,如下粗体所示:
namespace EssentialTools.Models
{
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 属性设置一个值。反映了对 NinjectDependencyResolver 类中的 AddBindings 方法所做的修改。注意,需要没置的属性名称是以字符串形式提供的。如下黑体所示:
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize",50M);
}
右键 Views 视图下的 Index.cshtml ,在浏览器中查看,可以看到如下所示效果:
如果需要设置多个属性值,可以链接调用 WithPropertyValue 方法,以涵盖所有这些属性,也可以用构造器参数做同样的事,如下粗体所示,重写 Discount.cs 文件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
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 绑定这个类,可以在 NinjectDependencyResolver 文件中修改 AddBindings 方法,使用 WithConstructorArgument 方法来指定构造器参数值。如下粗体所示:
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountSize", 50M);
}
同样,可以将这些方法调用连接在一起,已提供多值,并于依赖项混合和匹配, Ninject 会判断程序需要,并依此来创建他。这里,我不仅将方法改为 WithConstructorArgument ,也将 DiscountSize 改成 discountSize,用来匹配C#参数命名规则(参数首字母小写,属性首字母大写)。
使用条件绑定
Ninject 支持多个条件的绑定方法,这让程序能够指定内核用哪一个类对某一特定的接口进行响。为了演示这一特性,在示例项目的 Models 文件夹中添加了一个名称为 FlexibleDiscountHelper.cs 的新文件,其内容如下粗体所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
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("discountSize", 50M);
kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedExactlyInto<LinqValueCalculator>();
}
上述新绑定指明,在 Ninject内核要创建一个 LinqValueCalculator 对象时,应该使用 FlexibleDiscountHelper 类作为 IDiscounthelper 接口的实现。注意,我在适当的位置留下了对 IDiscountHelper 的原有绑定。 Ninject 会尝试找出最佳匹配,而且这有助于对同一个类或接口采用个默认绑定,以便在条件判据不能得到满足时,让 Ninject能够进行回滚。 Ninject有许多不同的条件绑定方法,最有用的一些条件绑定列于下表:
设置对象作用域
最后一个 Ninject 特性有助于调整 Ninject 所建对象的生命周期,以满足应用程序的需求。默认情况下, Ninject 会在每次请求一个对象时,为每个依赖项所需的各个对象创建一个新实例。为了演示所发生的情况,笔者修改了 LinqValueCalculator类的构造器,以便在每次创建个新实例时都向 Visual studio 的输出窗口写一条消息,如下粗体所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace EssentialTools.Models
{
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控制器,它要求从 Ninject 获得 lValueCalculator接口的两个实现,如下所示:
public HomeController(IValueCalculator calcParam,IValueCalculator calc2)
{
lvc = calcParam;
}
运行整个工程,效果如下:
反复地对 LinqValueCalculator 进行实例化不会有什么问题,但并非所有类都是这样。对于某些类,你会希望在整个应用程序*享一个单一的实例。而对于另一些类,又会希望为 ASP.NET 平台所接收到的每个HTTP请求,都创建一个新的实例。 Ninject 让你能够使用一种叫做“作用域( Scope)”的特性来控制所创建对象的生命周期,这是在建立接口与其实现之间的绑定时,通过方法调用来表示的。从下面代码可以看出如何将最有用的作用域运用于MVC框架的应用程序:在NinjectDependencyResolver 中将“请求作用域( Request Scope)”运用于 LinqValueCalculator 类(注意,在以下代码中,对 InRequestScope 方法的调用就是运用“请求作用域”)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using EssentialTools.Models;
using System.Web.Mvc;
using Ninject;
using Ninject.Web.Common;
namespace EssentialTools.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver(IKernel kekrnelParam)
{
kernel = kekrnelParam;
AddBindings();
}
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>().InRequestScope();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountSize", 50M);
kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedExactlyInto<LinqValueCalculator>();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
}
}
InRequestScope 扩展方法属于 Ninject.web.Common命名空间,这是告诉 Ninject,对于ASPNET所接收到的每一个请求,应该只创建 LinqValueCalculator类的一个实例。每一个请求都会获得各自独立的对象,但同一个请求中的多个依赖项将会用这个类的单一实例进行解析启动应用程序并查看 Visual studio输出窗口,便可以看到这种修改的结果,这表明 Ninject 仅创建了 LinqValueCalculator类的一个实例。如果刷新浏览器窗口但未重启应用程序,则会看到 Ninject 创建了第二个对象。 Ninject 提供了一系列不同的对象作用域。下表摘录了其中最有用的一些方法。
ASP.NET + MVC5 入门完整教程七 -—-- MVC基本工具(上)的更多相关文章
-
ASP.NET + MVC5 入门完整教程七 -—-- MVC基本工具(下)
https://blog.csdn.net/qq_21419015/article/details/80493633 Visual Stdio 的单元测试
-
ASP.NET + MVC5 入门完整教程四---MVC 中使用扩展方法
https://blog.csdn.net/qq_21419015/article/details/80433640 1.示例项目准备1)项目创建新建一个项目,命名为LanguageFeatures ...
-
ASP.NET + MVC5 入门完整教程三 (下) ---MVC 松耦合
建立松耦合组件 MVC 模式最重要的特性之一视他支持关注分离,希望应用程序中的组件尽可能独立,只有很少的几个可控依赖项.在理想的情况下,每个组件都不了解其他组件,而只是通过抽象接口来处理应用程序的其他 ...
-
ASP.NET + MVC5 入门完整教程八 -—-- 一个完整的应用程序(上)
https://blog.csdn.net/qq_21419015/article/details/80509513 SportsStore 1.开始创建Visual Studio 解决方案和项目这里 ...
-
ASP.NET + MVC5 入门完整教程三 (上) ---第一个MVC项目
https://blog.csdn.net/qq_21419015/article/details/80420815 第一个MVC应用程序 1创建MVC项目 打开VS ,File--新建--项目,选择 ...
-
ASP.NET + MVC5 入门完整教程八 -—-- 一个完整的应用程序(下)
https://blog.csdn.net/qq_21419015/article/details/80802931 SportsStore 1.导航 添加导航控件 如果客户能够通过产品列表进行分类导 ...
-
ASP.NET + MVC5 入门完整教程五 --- Razor (模型与布局)
https://blog.csdn.net/qq_21419015/article/details/80451895 1.准备示例项目 为了演示Razor,使用VS创建一个名称为“Razor”的新项目 ...
-
ASP.NET + MVC5 入门完整教程二
原文链接:https://blog.csdn.net/qq_21419015/article/details/80318046 从前端UI开始 MVC分离的比较好,开发顺序没有特别要求,先开发哪一部分 ...
-
MVC5+EF6 入门完整教程七
本篇我们针对表格显示添加一些新功能. 前面我们已经讲解过表格显示数据了,现在我们添加三个常用功能: 对显示结果进行排序.过滤.分页. 文章提纲 理论基础/前置准备 详细步骤 总结 前置准备 – 应用之 ...
随机推荐
-
VS一直停留在“正在还原nuget程序包”
VS一直停留在“正在还原nuget程序包” 在开发何问起收藏夹的时候,准备在WinFrom中加入网页浏览器,于是下载了一个CEFSharp的源码,生成解决方案的时候,一直提示“正在还原nuget程序包 ...
-
我的第一个GitHub仓库
GitHub 仓库地址 https://github.com/FBean/test.git GitHub 常用命令 add--Add file contents to the index bisect ...
-
我常用的delphi 第三方控件
转载:http://www.cnblogs.com/xalion/archive/2012/01/09/2317246.html 有网友问我常用的控件及功能.我先大概整理一下,以后会在文章里面碰到时再 ...
-
SpringAOP的注解方式
AOP(注解)[理解][应用][重点] 1.AOP注解配置流程 A.开启AOP配置支持注解@aspectj 核心配置文件中添加以下配置,功能等同于注解配置Bean的自动扫描路径 <aop:asp ...
-
ONFI闪存数据通道接口标准
早期的闪存产品每个厂家的设计标准各有不同,会碰到各种各样的问题,特别是到了06年之后,闪存产业市场需求开始发力,造成了迫切需要一个统一的标准来改变这个问题. 2007年1月,以英特尔,镁光,海力士,意 ...
-
它们的定义app.config中间section节点和在执行中使用
如果现在我们需要在app.config一个节点的在下面的例子中,定义,我们需要如何进行操作? <configSections> <section name="integra ...
-
MySQL字符串类型
VARCHAR类型用于存储变长字符串,它会删除末尾的所有空格,它比定长字符串更省空间,因为它仅使用必要的空间(越短的字符串占用越少),VARCHAR会用1或2个额外字节记录字符串长度(如果字符串长度不 ...
-
String String Buffer String Builder
如题,在java中这是一个典型的问题. 在*上已经有很多相似的问题被提问,并且有很多不正确或不完整的答案.如果你不往深处想,这是一个很简单的问题.但如果深入思考,它却很让人迷惑 ...
-
JS实现document.ready
通常我们想要在页面内容加载完成后运行 JS 时,都会使用 window.onload 来处理,比如: window.onload = function(){ alert('Hello World!') ...
-
mysql 5.6 解压缩版安装教程
MySQL 5.6 for Windows 解压缩版配置安装 听语音 | 浏览:68011 | 更新:2014-03-05 12:28 | 标签:mysql 1 2 3 4 5 6 7 分步阅读 My ...