.Net Core learning road - the use of AutoFac

This article does not introduce the concepts of IoC and DI. If you have no understanding of Ioc before, it is recommended to search for relevant information first.

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

Introduction to Autofac

Three ways to register components

  1. reflection
  2. ready-made instance (new)
  3. lambda expression (an anonymous method that executes an instantiated object)

The following are some brief examples. I will list as many common registration methods as possible, and explain the meaning of some terms such as "component" and "service" in the comments.

// 创建注册组件的builder
var builder = new ContainerBuilder();

//根据类型注册组件 ConsoleLogger 暴漏服务:ILogger
builder.RegisterType<ConsoleLogger>().As<ILogger>();

//根据类型注册组件 ConsoleLogger,暴漏其实现的所有服务(接口)
builder.RegisterType<ConsoleLogger>().AsImplementedInterfaces();

// 根据实例注册组件 output  暴漏服务:TextWriter
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>();

//表达式注册组件,这里我们是在构造函数时传参->"musection"   暴漏服务:IConfigReader
builder.Register(c =new ConfigReader("mysection")).As<IConfigReader>();

//表达式注册组件,解析时传参
var service = scope.Resolve<IConfigReader>(
           new NamedParameter("section", "mysection"));     

//反射注册组件,直接注册了ConsoleLogger类(必须是具体的类),如果ConsoleLogger有多个构造函数,将会取参数最多的那个构造函数进行实例化
builder.RegisterType<ConsoleLogger>();

//反射注册组件,手动指定构造函数,这里指定了调用 MyComponent(ILogger log,IConfigReader config)的构造函数进行注册
builder.RegisterType<MyComponent>()
 .UsingConstructor(typeof(ILogger), typeof(IConfigReader));  

 //注册MySingleton类中的静态变量"Instance",ExternallyOwned()函数指定自己控制实例的生命周期,而不是由autofac自动释放
 builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();

//一个组件暴漏两个服务  
builder.RegisterType<CallLogger>().As<ILogger>().As<ICallInterceptor>(); 

//注册当前程序集中以“Service”结尾的类
builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces();
//注册"MyApp.Repository"程序集中所有的类
builder.RegisterAssemblyTypes(System.Reflection.Assembly.Load("MyApp.Repository")).AsImplementedInterfaces();
  
//构建一个容器完成注册
var rootcontainer = builder.Build();

//可以通过下面这种方式手动获取IConfigReader 的实现类
//这种手动解析的方式需要 从生命周期作用域内获取组件,以保证组件最终被释放
//不要直接从根容器rootcontainer中解析组件,很有可能会导致内存泄漏
using(var scope = rootcontainer.BeginLifetimeScope())
{
  var reader = scope.Resolve<IConfigReader>();
}

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

The life cycle

using(var scope = rootcontainer.BeginLifetimeScope())

The above code creates a lifecycle scope

The life cycle scope is releasable, and the components resolved in the scope must ensure that they are used within the using or manually call the component's Dispose() function at the end

Avoid the life cycle of the referenced class is greater than the life cycle of the reference class: For example, if the service refers to the repository, if the life cycle of the repository is a singleton, the life cycle of the service is perrequest. The repository will not be released, so it will eventually cause the related service to never be released ( Captive Dependencies )

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

  • One instance per dependency (Instance Per Dependency) ( default ) ----InstancePerDependency()
  • Single instance (Single Instance) Single instance ----SingleInstance()
  • One instance per lifecycle scope (Instance Per Lifetime Scope)----InstancePerLifetimeScope()
  • One instance per matching life cycle scope (Instance Per Matching Lifetime Scope)----InstancePerMatchingLifetimeScope()
  • One instance per request (Instance Per Request) asp.net web request ----InstancePerRequest()
  • Each time an instance is owned (Instance Per Owned) ----InstancePerOwned()

If you've used autofac in a traditional ASP.NET MVC project before, there are some differences to note:

  • In .net Core, it is necessary to InstancePerLifetimeScopereplace the previous (traditional asp.net) to InstancePerRequestensure that only a unique dependency instance is created for each HTTP request. InstancePerRequestRequest level no longer exists
  • Web Api in .net Core is registered in the same way as Mvc
  • Controllers are no longer required to be registered in .net Core. Controllers are created by .net core and are not managed by autofac (except for the controller's constructor). This also explains why the InstancePerRequestlifecycle is no longer used, but it can be AddControllersAsServices()changed through functions. To learn more, check out: https://www.strathweb.com/2016/03/the-subtle-perils-of-controller-dependency-injection-in-asp-net-core-mvc/

The use of AutoFac in asp.net core

It is relatively simple to use autofac in .net core, which saves many steps compared to traditional asp.net web projects

Import 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)
    {
        //注册服务进 IServiceCollection
        services.AddMvc();
        ContainerBuilder builder = new ContainerBuilder();
        //将services中的服务填充到Autofac中.
        builder.Populate(services);
        //新模块组件注册
        builder.RegisterModule<DefaultModuleRegister>();
        //创建容器.
        AutofacContainer = builder.Build();
        //使用容器创建 AutofacServiceProvider 
        return new AutofacServiceProvider(AutofacContainer);
    }

The above code calls the builder RegisterModulefunction, which needs to pass in a TModulegeneric type called the autofac module

The function of the module is to put all the relevant registration configuration in one class, making the code easier to maintain and configure. The following shows the DefaultModuleRegistercode in

DefaultModuleRegister:

public class DefaultModuleRegister : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        //注册当前程序集中以“Ser”结尾的类,暴漏类实现的所有接口,生命周期为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();
        //注册所有"MyApp.Repository"程序集中的类
        //builder.RegisterAssemblyTypes(System.Reflection.Assembly.Load("MyApp.Repository")).AsImplementedInterfaces();
    }
}

The Configure function can optionally add the Autofac release function when the program stops:

    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?}");
        });
        //程序停止调用函数
        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, because we have filled the services in the IServiceCollection into autofac, the services (IConfiguration, IHostingEnvironment, etc.) that are injected by default by .net core can now be parsed through AutoFac anywhere.

In normal project use, we should put it AutofacContainerin a public class library so that each project can call it

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324582408&siteId=291194637