ASP.NET The whole process of implementing dependency injection in MVC

Time:2020-5-20

preface

There is an automatic injection function in Java spring, which makes the code more concise and flexible. Therefore, I want to transplant this function into C ා, and then analyze the implementation process step by step

1. Use automatic injection scenario analysis

stay asp.net In MVC, no matter what code logic layer is, the final presentation layer is controller layer, so our injection point is in controller. Here we need to replace the default controllerfactory, scan the code to mark the objects to be injected, and instantiate the injection

public class FastControllerFactory : DefaultControllerFactory
  {
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
      Type type = this.GetControllerType(requestContext, controllerName);
      Object obj = GetControllerInstance(requestContext, type);

      //Automatic injection of mark Autowired attribute in controller
      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 is a custom controller factory. It rewrites the createcontroller method, takes out the instance from the bean container and assigns a value to the variable marked with Autowired as the custom annotation. At the same time, we need to replace the default factory in the start method in the global file


ControllerBuilder.Current.SetControllerFactory(new FastControllerFactory());

2. Implementation of IOC container

There are many open-source mature frameworks for the custom containers in C, such as Autofac. Here we implement a lightweight version ourselves

Source address: https://gitee.com/grassprogramming/FastIOC

Here’s how to asp.net In MVC, first of all, we need to mark the bean object to be injected, which is called component,

stay asp.net In the start method in the MVC global file, we need to add the beans that need to be injected automatically in the whole project to the container

public class InjectUtil
  {
    public static ContainerBuilder Container;
    public static void Init()
    {
      Container = new ContainerBuilder();
       //Get all assemblies
      var assemblies = System.Web.Compilation.BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToArray();
      //Inject all Component
      Container.RegisterAssemblyTypes(assemblies, typeof(Component),true);
      Container.Build();
    }
  }

The controller level has been completed. Next, we need to initialize the bean instance method in the IOC container for further processing

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[] { });
      }
      //Here, the instance store is instantiated using the singleton mode to expose the object instances without subsequent settings in advance
      if (!SingleInstanceDic.ContainsKey(Entity.RealType))
      {
        SingleInstanceDic.Add(Entity.RealType, obj);
      }
    
      //If this class is marked with component, and there is a field marked with Autowired, perform automatic injection
      if (Entity.RealType.GetCustomAttribute(typeof(Component), true) != null)
      {
        //To use getruntimefields, this method returns all fields defined on the specified type, including inheritance, non-public, instance, and static fields.
        foreach (FieldInfo Field in Entity.RealType.GetRuntimeFields())
        {
          if (Field.GetCustomAttribute(typeof(AutoWired), true) != null)
          {
            Type FieldType = Field.FieldType;
            if (Contains(FieldType))
            {
              //Determine whether the singleton storage contains the value. If yes, take out the value assigned. This can prevent the dead cycle caused by circular dependency
              if (SingleInstanceDic.ContainsKey(FieldType))
              {
                Field.SetValue(obj, SingleInstanceDic[FieldType]);
              }
              else
              {
                Field.SetValue(obj, Resolve(FieldType));
              }
              
            }
          }
        }
      }
      return obj;

    }

GetInstance method is the core method to instantiate bean objects. In fact, it is very simple to create objects through reflection. There are two points to be noted

1) When a bean is initialized, all variables in the bean need to be scanned. If there are nested objects that depend on injection inside, recursion is needed until there is no field to be injected

2) I use the singleton mode here, because in the test process, there may be dependency injection to B in class A, dependency injection to a in class B. in the general creation process, if you use recursion to scan, you will enter a dead cycle and memory overflow. Therefore, once you create a singleton of an object, it will be put into a dictionary. If you scan the object again, you need to inject, It can be directly taken out for use, thus avoiding circular reference

3. Others

For other classes that are not used in the controller, dependency injection is needed, which needs to be taken out from the IOC bean container directly


 private AuthUtil @AuthUtil = InjectUtil.Container.Resolve<AuthUtil>();

All the functions are analyzed here. At last, make an advertisement and write it by yourself ASP.NET MVC rapid development framework, hope to support a wave

Address: https://gitee.com/grassprogramming/FastExecutor

summary

The above is the whole content of this article. I hope that the content of this article has some reference learning value for your study or work. Thank you for your support for developepaer.