第08章 ASP.NET 5:依赖注入
1.背景
如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口。简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程。
那么问题来了?如何选择客户程序所需要的实现类?在使用创建型模式下创建对象是不难解决这个问题。
但如果设计的不是具体业务逻辑,而是公共类库或框架程序,对外只提供抽象而已,该如何把外部使用的类型传递给它们?
我们可以采用“依赖注入”的方式,将加工好的抽象类型实体“注入”到客户程序中。
注:依赖注入DI(Dependency Injection),它和控制反转IOC(Inversion of Control)是同一个意思,不同术语叫法。
2.场景
客户程序获取年份,我们先设计一个接口:
using System; namespace Blog.Consoles { public interface ITimeProvider { DateTime CurrentDate { get; } } }
并对这个接口实现(可以多种实现哦,这也是设计接口的原因):
using System; namespace Blog.Consoles { public class TimeProvider : ITimeProvider { public DateTime CurrentDate { get { return DateTime.Now; } } } }
那么我们在客户程序使用:
using System; namespace Blog.Consoles { class Program { static void Main(string[] args) { ITimeProvider tp = new TimeProvider(); Console.WriteLine(tp.CurrentDate.Year); Console.ReadKey(); } } }
这样实现的依赖关系是:
显然这样客户程序还需要知道具体类型TimeProvider,我们增加一个对象:
using System; using System.Collections.Generic; namespace Blog.Consoles { public class Assembler { //保存抽象类型和实体类型 static Dictionary<Type, Type> d = new Dictionary<Type, Type>(); static Assembler() { //注册抽象类型需要使用的实体类型 d.Add(typeof(ITimeProvider), typeof(TimeProvider)); } public object Create(Type type) { if ((type == null) || !d.ContainsKey(type)) { throw new NullReferenceException(); } return Activator.CreateInstance(d[type]); } public T Create<T>() { return (T)Create(typeof(T)); } } }
此时再改造依赖关系:
这样客户程序只依赖Assembler和ITimeProvider,并不知道TimeProvider存在。
接下来如何写注入代码?下面分几种方式。
3.构造注入
构造注入使用构造方法,通过Assembler或其它机制把抽象类型作为参数传递。其实现代码:
using System; namespace Blog.Consoles { class Program { public ITimeProvider _tp; public Program(ITimeProvider tp) { _tp = tp; } public int GetYear() { return _tp.CurrentDate.Year; } static void Main(string[] args) { ITimeProvider time = new Assembler().Create<ITimeProvider>(); Program p = new Program(time); Console.WriteLine(p.GetYear()); Console.ReadKey(); } } }
4.设置注入
通过属性方法赋值实现的,相对于构造方法一次性注入的方式,设置注入可以在需要时有更改的机会。实现代码:
using System; namespace Blog.Consoles { class Program { public ITimeProvider _tp { get; set; } public int GetYear() { return _tp.CurrentDate.Year; } static void Main(string[] args) { ITimeProvider time = new Assembler().Create<ITimeProvider>(); Program p = new Program(); p._tp = time; Console.WriteLine(p.GetYear()); Console.ReadKey(); } } }
还可以简写:
using System; namespace Blog.Consoles { class Program { public ITimeProvider _tp { get; set; } public int GetYear() { return _tp.CurrentDate.Year; } static void Main(string[] args) { var p = new Program() { _tp = new Assembler().Create<ITimeProvider>() }; Console.WriteLine(p.GetYear()); Console.ReadKey(); } } }
5.MEF注入
导出部件:
下面不使用Assembler对象,实现代码:
using System; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; namespace Blog.Consoles { class Program { private static CompositionContainer container; private void Compose() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); container = new CompositionContainer(catalog); //将部件和宿主程序添加到组合容器 container.ComposeParts(this, new TimeProvider()); } //导入部件 [Import] public ITimeProvider _tp { get; set; } public int GetYear() { return _tp.CurrentDate.Year; } static void Main(string[] args) { var p = new Program(); p.Compose(); Console.WriteLine(p.GetYear()); Console.ReadKey(); } } }
6.ASP.NET 5注入
修改Startup.cs:
测试:
7.小结
关于依赖注入的方式,还是接口注入,自定义特性等(它们之间区别和选择,自行体会或查资料),不常用就不说了。
感受到ASP.NET 5自带DI爽就行啦!(ASP.NET 5真的海皮啦!)
后面的帖子,进入项目实战了,最近比较忙,请园友保持耐心。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。