ASP.NET Implementation of pseudo attribute injection in core

Time:2021-2-10

1、 Preface

I have not updated my blog for a long time, and I have been adjusting my status. Last year was my year of life. Maybe it was the realization of my year of life. I had a very bad life, both in life and work. Fortunately, many things are getting better after I have passed the so-called Benming year. I will start to update my blog and try to get back to the previous speed (because I am busy with work, this process may take a while).

2、 About attribute injection

When it comes to attribute injection, we have to mention di (dependency injection), that is, dependency injection ASP.NET Core students believe that this word is not strange. ASP.NET The core comes with an IOC container, and the program running is also based on this container, which is in startupConfigureServicesThe method is to register the type with the container. To put it bluntly, we are here ASP.NET In core, if you want to use a type, you don’t need to go to new by yourself. You can inject specific implementation types through construction methods by the container. However, the dependency types that we usually define in construction methods are interfaces, rather than relying on specific implementations. This reflects the dependency inversion principle (dip) in solid principle. This is also IOC (inversion of control), that is, the inversion of control, which does not directly depend on the specific implementation, but leaves the dependency to the container to control. Dip is a software design principle, IOC is the specific implementation of dip, Di is an implementation of IOC.

In dependency injection, the most common way is to construct method injection, and another way is attribute injection.

As for attribute injection, if you search on the Internet, most of the content is not recommended or used cautiously, because attribute injection will cause type dependency hiding, test unfriendly, etc. I also agree with this view. Attribute injection can be used, but we should be careful and not use it blindly. My principle: it can be used when encapsulating the framework (building a shelf), but it can not be used in a wide range. It can only be used where attribute injection must be used to achieve the effect. It can be used to improve the coding efficiency when using the framework, so as to achieve some convenience. It can not be used when writing business code without framework level.

In ASP.NET In the core, the built-in container does not support attribute injection, but it can be implemented by replacing the container, such as Autofac. The method I share today is not to use the replacement container, but to achieve the effect of attribute injection through a few lines of code, which I call “pseudo attribute injection”.

3、 The pain point of attribute injection

The pain points described below are some of the ones I encountered in the actual coding process. If there are others, please comment and communicate with me

The pain points I encountered can be summarized into three points

1. Reduce the repeated injection code of common types, make the construction method look more concise and improve the readability.

2. Reduce or eliminate the base call chain after subclass inheritance caused by construction method injection.

3. It is not necessary to use attribute injection to solve the problem if the first or second item is satisfied. Only when the first or second item occurs in a certain number of cases.

Article 1:

In the form of logILogger<T>For example, we may often use it in the controller or application service layer to write business, so we may write an injection sentence in most of the controller or application service construction methods, for example:

Here we just take logs as an example. We can also encounter the same type as logs. Each controller needs to inject a pile of this common type. It’s troublesome to write code. If there are too many, it will affect the code reading.

What is the solution? That is to define a base class and provide it to subclasses through attributes. Take controller as an example:

Article 2:

Inject ilogger into the above controller base class, and then set the logger property, so that the subclass can use the logger property to use the log.

In this way, base is called every time to pass the dependent object to the base class. If there are multiple layers of inheritance, it will have a greater impact.

Note: this demonstration only takes logs as an example. If there is only one ilogger, I think it is tolerable. In fact, there is not only one ilogger, such as localization and so on. Bloggers don’t advocate using attribute injection when the above demonstration situation exists. It can only be used when a certain number of objects is reached, such as a large number of objects in controller or application service, and when the common injection type of these objects reaches a certain number.

4、 The core idea of pseudo attribute injection

Rely on ASP.NET The container provided by the core can be used to assign values to the attributes that need “attribute injection” during resolve serviceImplementationFactoryTo achieve.

5、 Implement pseudo attribute injection for controller

The implementation of controller is special. By default, the controller does not resolve & activate through its own container, but is managed through MVC itself. However, Microsoft provides this method:


services.AddControllers().AddControllersAsServices();

You can callAddControllersAsServices() Method to let the controller use its own container. The main source code is as follows

According to the idea in the fourth section, we need to assign values to properties when we need controller resolve, so we need to modify the controller activator.

Define the controller base class

Controller inherits the base class

Modifying controller activator

You can see that the code we modified is just a few lines.

Replace default controller activator

services.AddControllers().AddControllersAsServices();
services.Replace(ServiceDescriptor.Transient<IControllerActivator, XcServiceBasedControllerActivator>()); 
//Replace default controller activator

Run the test

The test is normal. If you need “attribute injection” of other attributes, just refer to the log.

6、 Implement pseudo attribute injection for application service

Just use the application service as an explanation. Similarly, you can draw inferences from one instance to other places. Application service belongs to a layer of Domain Driven hierarchical architecture. If you don’t know about it, you can search for information by yourself.

Define application service base class interface


public interface IAppService
{
  ILogger Logger { get; set; }
}

public class AppService:IAppService
{
  public ILogger Logger { get; set; }
}

Define specific services, taking user service as an example

public interface IUserAppService:IAppService
{
  void Create();
}

public class UserAppService : AppService,IUserAppService
{
  public void Create()
  {
    Logger.LogInformation ("log from application service");
  }
}

Define the method of special registration service, so as to realize the assignment of resolver to logger

public static class ServiceExtensions
{
  public static IServiceCollection AddApplicationService<TService, TImpl>(this IServiceCollection services) where TService:IAppService where TImpl:AppService
  {
    services.AddApplicationService(typeof(TService), typeof(TImpl));
    return services;
  }
  //This method can be called by reflection assembly to achieve batch automatic registration of application services
  public static IServiceCollection AddApplicationService(this IServiceCollection services, Type serviceType,Type implType)
  {
    services.AddTransient(serviceType, sp =>
    {
      //Get the instance of the service implementation
      var implInstance = ActivatorUtilities.CreateInstance(sp, implType); ;

      if (implInstance is AppService obj)
      {
        //Assign value to logger
        obj.Logger= sp.GetRequiredService<ILoggerFactory>().CreateLogger(implType);
      }
      
      return implInstance;
    });
    return services;
  }

Registration test service

Controller injection test service

Run the test

7、 It’s over

In fact, after writing this article, I was thinking about whether to package a component and publish it to nuget to facilitate the use of the “pseudo attribute injection” I described in this article. Finally, I thought about it again and again, but I still didn’t think about it. If you want to use complete attribute injection, you can replace the use of third-party containers. The purpose of this article is not to introduce third-party containers, and to achieve the effect of attribute injection in some places, because attribute injection is not recommended to be widely used.

This article comes from my work in some inspiration summary, I am looking at ControllerActivatorAlthough I have been busy recently, I have accumulated a lot of knowledge. I will share it with you one by one later.

Sister:ASP.NET Dynamic webapi of core

This is about ASP.NET This is the article about the implementation of pseudo attribute injection in core technology, and more about it ASP.NET Core pseudo property injection content, please search previous articles of developer or continue to browse the following related articles. I hope you can support developer more in the future!

Author: Xiaochen master (Li Zhiqiang)

Article link: https://www.cnblogs.com/stulzq/p/12610026.html