Use of AutoFac of Net Core

  • 2021-11-29 23:41:00
  • OfStack

The directory Autofac introduces the three ways to register components. Life cycle AutoFac is used in asp. net core

This article does not introduce the concepts of IoC and DI. If you don't know Ioc before, it is recommended to search for relevant information under 1 first

This article will briefly introduce the basic use of AutoFac under 1 and its application in asp. net core

Introduction to Autofac

Three ways to register components

1. Reflex

2. Ready-made examples (new)

3. lambda expression (1 anonymous method that executes an instantiated object)

Here are a few short examples. I will list as many common registration methods as possible, and explain the meanings of the terms "component" and "service" in the comments


//  Object for a registered component builder
var builder = new ContainerBuilder();

// Register components by type  ConsoleLogger  Leak service: ILogger
builder.RegisterType<ConsoleLogger>().As<ILogger>();

// Register components by type  ConsoleLogger, Expose all services (interfaces) it implements 
builder.RegisterType<ConsoleLogger>().AsImplementedInterfaces();

//  Register components according to instances  output   Leak service: TextWriter
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>();

// Expression registers the component, where we pass parameters when constructing the function ->"musection"    Leak service: IConfigReader
builder.Register(c =new ConfigReader("mysection")).As<IConfigReader>();

// Expression registration component , Analytic time transmission parameter 
var service = scope.Resolve<IConfigReader>(
           new NamedParameter("section", "mysection"));     

// Reflection registration component, which directly registers ConsoleLogger Class (must be a concrete class), if ConsoleLogger There are multiple constructors, and the constructor with the most parameters will be instantiated 
builder.RegisterType<ConsoleLogger>();

// Reflection registration component, manually specify the constructor, which specifies the call  MyComponent ( ILogger log,IConfigReader config ) to register the constructor of 
builder.RegisterType<MyComponent>()
 .UsingConstructor(typeof(ILogger), typeof(IConfigReader));  

 // Registration MySingleton Static variables in the class "Instance" , ExternallyOwned() Function specifies the life cycle of its own control instance, instead of being defined by the autofac Automatic release 
 builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();

//1 Two services are exposed by two components   
builder.RegisterType<CallLogger>().As<ILogger>().As<ICallInterceptor>(); 

// Registers the current assembly with the Service "Ending class 
builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces();
// Registration "MyApp.Repository" All classes in the assembly 
builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces();
  
// Build 1 Containers complete registration 
var rootcontainer = builder.Build();

// You can get it manually in the following way IConfigReader  Implementation class of 
// This manual parsing method requires   Getting Components from Lifecycle Scope , To ensure that the component is finally released 
// Do not go directly from the root container rootcontainer Parsing components in, it is very likely that memory leaks will be caused 
using(var scope = rootcontainer.BeginLifetimeScope())
{
  var reader = scope.Resolve<IConfigReader>();
}

If more than one component exposes the same service, Autofac uses the last registered component as the service provider. To override this behavior, use the PreserveExistingDefaults() Method modification

Life cycle

using(var scope = rootcontainer.BeginLifetimeScope())

The above code creates a life cycle scope

The lifecycle scope is releasable, and component 1 resolved within the scope must be guaranteed to use within using or finally manually call the component's Dispose () function

Avoid the life cycle of the referenced class being longer than the life cycle of the referenced class: if service references repository, if the life cycle of service is a singleton, the life cycle of repository is perrequest. service will not be released, so eventually the associated repository will never be released (Captive Dependencies)

Although we need to avoid parsing components directly from the root container as much as possible, there are always exceptions. For non-singleton components, 1 don't forget to call the Dispose function of the component. In fact, for non-singleton components, from the project architecture, in theory, it should be injected from the constructor instead of manually parsing. What needs to be parsed manually should be 1 configuration help class, etc.

The life cycle of a specific component (class) is divided into the following types (the latter functions are the functions corresponding to autofac):

Dependent on 1 instance each (Instance Per Dependency) (default)--InstancePerDependency () Single 1 instance (Single Instance) Single case--SingleInstance () 1 instance per lifecycle scope (Instance Per Lifetime Scope)--InstancePerLifetimeScope () 1 instance per matched lifecycle scope (Instance Per Matching Lifetime Scope)--InstancePerMatchingLifetimeScope () 1 instance per request (Instance Per Request) asp. net web Request--InstancePerRequest () Have 1 instance at a time (Instance Per Owned)--InstancePerOwned ()

If you have used autofac in the traditional ASP. NET MVC project before, there are one differences to note:

. required in net Core InstancePerLifetimeScope Replace the previous (traditional asp. net) InstancePerRequest Ensuring that only 1 dependent instance is created per HTTP request. InstancePerRequest The request level no longer exists The registration mode of Web, Api and Mvc in net, Core Registered controllers are no longer required in. net Core. The controllers are created by. net core and are not managed by autofac (except for the controller constructor), which explains why they are no longer used InstancePerRequest Life cycle, but it can be passed through AddControllersAsServices() Function changes, you can see: https://www.strathweb.com/2016/03/the-subtle-perils-of-controller-dependency-injection-in-asp-net-core-core-mvc/

Application of AutoFac in asp. net core

Using autofac in. net core is still relatively simple. Compared with the traditional asp. net web project, many steps are omitted

Introducing the nuget package:

Autofac Autofac.Extensions.DependencyInjection

Code in startup:


  public static IContainer AutofacContainer;
    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // Registration service entry  IServiceCollection
        services.AddMvc();
        ContainerBuilder builder = new ContainerBuilder();
        // Will services To populate the service in the Autofac Medium .
        builder.Populate(services);
        // New module component registration 
        builder.RegisterModule<DefaultModuleRegister>();
        // Create a container .
        AutofacContainer = builder.Build();
        // Using containers to create  AutofacServiceProvider 
        return new AutofacServiceProvider(AutofacContainer);
    }

The above code calls builder's RegisterModule Function, which requires passing in 1 TModule A module called autofac

The function of the module is to put all the relevant registration configurations in one class, which makes the code easier to maintain and configure, as shown below DefaultModuleRegister Code in

DefaultModuleRegister:


public class DefaultModuleRegister : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // Registers the current assembly with the Ser "Ending class , All interfaces implemented by the burst class, with a life cycle of PerLifetimeScope
        builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Ser")).AsImplementedInterfaces().InstancePerLifetimeScope();
        builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerLifetimeScope();
        // Register all "MyApp.Repository" Classes in an assembly 
        //builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces();
    }

	public static Assembly GetAssembly(string assemblyName)
    {
        var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(AppContext.BaseDirectory + $"{assemblyName}.dll");
        return assembly;
    }
}

The release function of Autofac when the program stops can be selectively added to the Configure function:


  public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
        // The program stops calling the function 
        appLifetime.ApplicationStopped.Register(() => { AutofacContainer.Dispose(); });
    }

Code in Controller:


  private IUserSer _user;
    private IUserSer _user2;
    public HomeController(IUserSer user, IUserSer user2)
    {
        _user = user;
        _user2 = user2;
    }
    public IActionResult Index()
    {
        using (var scope = Startup.AutofacContainer.BeginLifetimeScope())
        {
            IConfiguration config = scope.Resolve<IConfiguration>();
            IHostingEnvironment env = scope.Resolve<IHostingEnvironment>();
        }
        string name = _user.GetName();
        string name2 = _user2.GetName();
        return View();
    }

As you can see, since we populated the services in IServiceCollection into autofac, we can now parse the services from AutoFac anywhere. The default injected services from net core (IConfiguration, IHostingEnvironment, etc.)

In normal project use, we should put using(var scope = rootcontainer.BeginLifetimeScope())0 Put it in a common class library so that all projects can call


Related articles: