ASP.NET MVC实现依赖注入的完整过程
前言
在java的spring中有自动注入功能,使得代码变得更加简洁灵活,所以想把这个功能移植到c#中,接下来逐步分析实现过程
1.使用自动注入场景分析
在asp.net mvc中,无论是什么代码逻辑分层,最终的表现层为controller层,所以我们注入点就是在controller中,这里我们需要替换默认的controllerfactory,扫描代码中标记需要注入的对象,进行实例化注入
public class fastcontrollerfactory : defaultcontrollerfactory { public override icontroller createcontroller(requestcontext requestcontext, string controllername) { type type = this.getcontrollertype(requestcontext, controllername); object obj = getcontrollerinstance(requestcontext, type); //controller中标记autowired属性的自动注入 list<fieldinfo> autowiredfieldlist = type.getruntimefields().where(f => f.getcustomattribute(typeof(autowired)) != null).tolist(); foreach (fieldinfo field in autowiredfieldlist) { field.setvalue(obj, injectutil.container.resolve(field.fieldtype)); } return obj as icontroller; } }
fastcontrollerfactory就是我们自定义的一个controller工厂,重写createcontroller方法,对标记了autowired这个自定义注解的变量,从bean容器中取出实例进行赋值,同时我们还需要在global文件中的start方法中,进行默认工厂进行替换
controllerbuilder.current.setcontrollerfactory(new fastcontrollerfactory());
2.ioc容器的实现
c#中的自定义容器有很多开源成熟的框架,例如autofac等,这里我们是自己实现一个轻量级的版本
源码地址:https://gitee.com/grassprogramming/fastioc
这里就重点说一下如何在asp.net mvc中的使用,首先我们需要对需要注入的bean对象进行标记,这个标记就叫做component,
在asp.net mvc global文件中的start方法中,我们需要将整个项目中需要自动注入的bean加入到容器中
public class injectutil { public static containerbuilder container; public static void init() { container = new containerbuilder(); //获取所有程序集 var assemblies = system.web.compilation.buildmanager.getreferencedassemblies().cast<assembly>().toarray(); //注入所有component组件 container.registerassemblytypes(assemblies, typeof(component),true); container.build(); } }
到这里controller层面的事项就已经完成了,接下来就需要在ioc容器中初始化bean实例方法中进一步处理
private object getinstance(registerentity entity) { object obj = null; if (entity.isenableintercept) { bool isextend = entity.realtype == entity.registtype; obj = dynamictproxy.createproxyobject(entity.realtype, entity.registtype, entity.intercepttype, isextend, entity.isinterceptallmethod); } else { var constructors = entity.registtype.getconstructors(); obj = constructors[0].invoke(new object[] { }); } //这里使用单例模式将实例化instance存储,提前暴露未进行后续设置的对象实例 if (!singleinstancedic.containskey(entity.realtype)) { singleinstancedic.add(entity.realtype, obj); } //如果这个class标记了component,且有标记了autowired的field,进行自动注入 if (entity.realtype.getcustomattribute(typeof(component), true) != null) { //这里要使用getruntimefields,此方法返回在指定类型上定义的所有字段,包括继承,非公共,实例和静态字段。 foreach (fieldinfo field in entity.realtype.getruntimefields()) { if (field.getcustomattribute(typeof(autowired), true) != null) { type fieldtype = field.fieldtype; if (contains(fieldtype)) { //判断单例存储中是否包含,如果有,取出赋值,这里可以防止循环依赖导致的死循环 if (singleinstancedic.containskey(fieldtype)) { field.setvalue(obj, singleinstancedic[fieldtype]); } else { field.setvalue(obj, resolve(fieldtype)); } } } } } return obj; }
getinstance方法就是实例化bean对象的核心方法,其实很简单,就是通过反射创建对象,其中需要注意的有两点
1)对于一个bean初始化时需要扫描bean中的所有变量,如果内部还有依赖注入的嵌套对象,需要使用递归,直到没有需要注入的field
2)我这里使用的是单例模式,因为在测试过程中可能存在在a类中对b进行依赖注入,在b类中对a进行依赖注入,常规创建过程,如果使用递归进行扫描,就会进入死循环,内存溢出,所以使用对象的单例,一旦创建就放入字典中,如果再次扫描到该对象需要注入,则直接取出使用,就避免了循环引用
3.其他
对其他不在controller中使用的类需要依赖注入,则需要直接从ioc的bean容器取出使用
private authutil @authutil = injectutil.container.resolve<authutil>();
功能到这里就全部分析完毕了,最后打个广告,自己写的asp.net mvc快速开发框架,希望支持一波
地址:https://gitee.com/grassprogramming/fastexecutor
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
推荐阅读
-
浅析PHP类的反射来实现依赖注入过程
-
转载——Asp.Net MVC+EF+三层架构的完整搭建过程
-
asp.net core 依赖注入实现全过程粗略剖析(2)
-
asp.net core 依赖注入实现全过程粗略剖析(1)
-
asp.net core 依赖注入实现全过程粗略剖析(3)
-
在ASP.NET MVC中使用Unity进行依赖注入的三种方式
-
ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)
-
ASP.NET Core 2.0使用Autofac实现IOC依赖注入竟然能如此的优雅简便
-
ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)
-
浅析PHP类的反射来实现依赖注入过程