欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET MVC实现依赖注入的完整过程

程序员文章站 2022-04-29 09:54:38
前言 在java的spring中有自动注入功能,使得代码变得更加简洁灵活,所以想把这个功能移植到c#中,接下来逐步分析实现过程 1.使用自动注入场景分析 在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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。