今天的主题是ASP.NET MVC中的依赖注入这些事,依赖注入开始是叫做IoC也就是控制反转了,后来被rename了。废话到此结束。那么我们为什么要在ASP.NET MVC中时候DI呢?这DI有什么神奇的地方让ASP.NET MVC如此的爱它。为了解决这个问题呢,我们先来看看,为什么要依赖注入。其实在MVC中一个重要的特征就是关注分离,我们希望我们的应用程序尽可能的相互独立,尽可能的减少彼此的依赖,一个理想的应用程序应当是一个组件可以不知道或者说不关心其它组件的存在,但是可以通过一个公开的接口可以调用其它的组件。这也就是所谓的松耦合。
这里可以举一个很简单的例子说明。比如我定义了一个接口IprintStr,在这个接口里就是一个方法,string printName(string name);之后呢,我们再定义一个类来继承这个接口:printStr:IprintStr.类的具体实现我这里不再累赘。现在呢我们要实现这个类提供的服务操作,我们再定义一个类。叫做execute.cs我们在这个execute.cs类中可以这么写:IprintStr str = new printStr(); string myName = str.printName(“David Zhang”);之后输出。到此这个例子就结束了。我们接着来思考下。在我们这个简单例子中execute类是通过IprintStr接口而不是直接通过printStr类实现,如果以后我这个execute要发生大的变化,要实现其他的功能,那么我可以这样写 IprintStr str = new xxxXX();也就是换掉new后面的对象。其他的代码保持不变。在这里呢我们实现了一定的松耦合。在这个例子中呢,我们的printStr类既依赖于IprintStr也依赖于execute类。在这里呢就会出现这样一个问题,加入有一天我们这个printStr类出现了莫名其妙的问题,那么是不是我们的execute这个类也要进行维护。这是很麻烦的一件事。最好的办法就是,这里的IprintStr,printStr和execute三个不同的组件相互的分开,彼此之间没有半毛钱的关系。而我们的依赖注入就是为了解决这样的问题!
什么是依赖注入
其实在应用程序中呢,在一个执行类中,不通过创建服务类的对象的实例,我们就可以获得某个公开接口的对象的引用。也可以这么说依赖注入是一个过程,由于执行类只依赖于服务类的一个接口,而不依赖于具体的服务类,所以呢,在客户类中只定义一个注入点,在程序运行的时候,执行类不直接实例化服务类的具体兑现,而是执行类运行上下文的专门的组件来负责实例化服务类,之后呢,将其注入到执行类中。这样,执行类得以正常的运行。
依赖注入的类别
这里我就说下setter注入和构造注入吧。其它的不怎么用
首先是setter注入:也就是在执行类中,设置一个服务类接口类型的数据成员,并且设置一个set方法作为注入点,这个set方法接受一个具体服务类实例作为参数,并且把它赋给服务类接口类型的数据成员
public class execute
{
IprintStr printStr;
public void set_execute(IprintStr printStr)
{
this.printStr = printStr;
}
public string printNameFun(string name)
{
string testExam= printStr.printName(name);
return testExam;
}
}
还有一个就是构造注入(Constructor Injection)
public class execute
{
IprintStr printStr;
public execute(IprintStr printStr)
{
this.printStr = printStr;
}
public string printNameFun(string name)
{
string testExam= printStr.printName(name);
return testExam;
}
}
构造注入呢,也就是setter注入方法变成了构造方法。这里要注意的是,构造注入只能注入一次,在程序运行期间,没有办法改变执行类中的服务类对象实例。
到了这里,我们不得不谈到Ioc Container.
用于实现依赖注入的框架或者是组件就是Ioc Container.比如java平台十分成熟的重量级Ioc Container Sping和一直到.net平台的Spring.net.以及一些轻量级的Ioc Container比如本文要说的unity和ninject。
我们先说说ninject吧!
如何得到。我们可以通过vs中的NuGet包管理器进行下在,它自动可以添加到相关的namespace到你的项目中,我们要做的就是在要的时候,using下!我这里已经using了,下面就很简单了。
1: static void Main(string[] args)
2: {
3: IKernel ninjectKernel = new StandardKernel();
4: //绑定接口道实现该接口的类
5: ninjectKernel.Bind<IprintStr>().To<recName>();
6: //获得实现接口的对象实例
7: IprintStr iprintStr = ninjectKernel.Get<IprintStr>();
8: //创建recName实例并且实现注入依赖
9: string str = iprintStr.printName("This is David Zhang Home Page.");
10: Console.WriteLine(str);
11: Console.ReadKey();
12: }
这里我们还是应用上面我们谈的例子。关键部分上面已经注释了!我在这里就不再累赘了,这里的recName就是开始我们说的实现IprintStr的printStr,因为有些变动没有改过来!。关于具体的ninject的API,你可以Google。我这里不再多篇幅的说明。我们就用在ASP.NET MVC 中使用的unity Container吧,因为最近的项目里用到了它,同时希望这边博文给正在做项目的朋友们以参考。只当是抛砖引玉吧。
Ioc可以对ASP.NET MVC 的Controller进行注入,要想实现Controller的依赖注入,就需要让IoC容器接管Controller的创建,而ASP.NET MVC 3中提供的IDependencyResolver接口就为实现这个提供了可能。所以,我们首先创建一个实现IDependencyResolver接口的UnityDependencyResolver类,
1: public class UnityDependencyResolver : IDependencyResolver
2: {
3: IUnityContainer container;
4: public UnityDependencyResolver(IUnityContainer container)
5: {
6: this.container = container;
7: }
8:
9: public object GetService(Type serviceType)
10: {
11: try
12: {
13: return container.Resolve(serviceType);
14: }
15: catch
16: {
17: return null;
18: }
19: }
20:
21: public IEnumerable<object> GetServices(Type serviceType)
22: {
23: try
24: {
25: return container.ResolveAll(serviceType);
26: }
27: catch
28: {
29: return new List<object>();
30: }
31: }
32: }
这里对null的说明:在IDependencyResolver.GetService(Type serviceType)的实现中,判断一下serviceType是否被注册,如果没有被注册,就返回null。ASP.NET MVC得到null返回值,会自己解析这个接口。好了,我们现在实现了这个IDependencyResolver。还有一个很重要的一点就是你要告诉MVC,在这里我们创建了unityDependencyResolver,他要被解析,我们可以在Global.asax的Application_Start()中添加:
IUnityContainer container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
当然了,说到这里,还有一点我们没有涉及,大家可以看到上面我用ninject写的一个小例子,它有一个ninjectkernel.Bind<Ixxx>().To<xxx>().这个通俗的时候也就是注册,世间万物都是相似的,我们在unity中也有类似的,如:
container.RegisterType<Ixxx, xxx>();那么我们如何进行注册呢,有连个办法:第一就是在你需要的Controller中进行相关的注册,或者将所有的注册相关的代码统一到一个类文件中, 比如类:DependencyRegisterType,将所有的注册写到一个静态的方法中,之后再Application_Start()中进行运行。最后一点就是在相关的Controller中要这样写:
[Dependency]
public IxxxL _xxxL { get; set; }
之后进行相关的调用。编程效率那是大大的增加啊!!省去了不少new.
okay,That’s all.时间不早了,Good Night
关于本博文声明:
本博文属于原创博文,允许转载。但要保留原链接!由于时间仓促,没有细心校对,博文可能有些地方不完善或者说是有错误。欢迎雅正:)
博文部分参考:
http://www.cnblogs.com/dudu/archive/2011/06/09/unity_mvc_idependencyresolver.html
http://www.cnblogs.com/techborther/archive/2012/01/06/2313498.html