在ASP.NET Core中使用Autofac增强容器能力

前言

当前引入了NuGet包

$ Install-Package Autofac.Extras.DynamicProxy -Version 4.5.0
$ Install-Package Autofac.Extensions.DependencyInjection -Version 5.0.1

一、什么情况需要引入第三方容器组件

  • 基于名称的注入 - 按照名称来区分它不同的实现的时候
  • 属性注入 - 直接把服务注册到某一个类的属性中
  • 子容器
  • 基于动态代理的AOP

二、用Autofac覆盖默认的Ioc

在引入两个 Autofac 的包后
Program 中注册 Autofac ,使用 UseServiceProviderFactory() 方法

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        	// 重写用于创建服务提供程序的工厂
        	// 把AutofacServiceProviderFactory注册进去
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webBuilder =>
            {
    
    
                webBuilder.UseStartup<Startup>();
            });

然后在 Startup 中添加一个 ConfigureContainer() 方法
原本存在的 ConfigureServices() 方法是注入默认的容器,
服务注册进默认的容器以后会被 Autofac 接替,
然后执行 ConfigureContainer() 方法。

三、使用方式

用Autofac覆盖默认的Ioc后

1) 普通注册

使用 Autofac 的注册方式和 默认的Ioc 框架注册方式略有不同。

	public void ConfigureContainer(ContainerBuilder builder)
    {
    
    
    	// 先注册具体实现,然后是标记为哪个服务类型
		builder.RegisterType<T>().As<IT>();
	}

使用时

	public void Configure(IApplicationBuilder app)
	{
    
    
		// 也可以直接在构造函数中请求 ILifetimeScope  
		ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot();
		IT t = AutofacContainer.Resolve<IT>();
	}

2) 基于名称注册

当我们需要将一个服务注册多次,并用不同命名来区分时

	public void ConfigureContainer(ContainerBuilder builder)
    {
    
    
    	// 使用Named
		builder.RegisterType<T>().Named<IT>("service2");
	}

使用时

	public void Configure(IApplicationBuilder app)
	{
    
    
		// 也可以直接在构造函数中请求 ILifetimeScope  
		ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot();
		IT t = AutofacContainer.ResolveNamed<IT>("service2")
	}

3) 属性注入

属性注入使用 PropertiesAutowired() 方法

	#region Class
	public class T: IT
    {
    
    
        public Attribute Attr {
    
     get; set; }
    }
    
	public class Attribute {
    
     }
	#endregion
	
	public void ConfigureContainer(ContainerBuilder builder)
    {
    
    
    	// 属性注入
    	builder.RegisterType<Attribute>();
		builder.RegisterType<T>().As<IT>().PropertiesAutowired()
	}

使用时 Attr 属性不为 null

	public void Configure(IApplicationBuilder app)
	{
    
    
		// 也可以直接在构造函数中请求 ILifetimeScope  
		ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot();
		// t 的 Attr 属性不为 null
		IT t = AutofacContainer.Resolve<IT>();
	}

4) AOP

我们在不期望改变原有类的情况下,在方法执行时嵌入一下逻辑,
让我们可以在方法执行的切面上任意插入我们的逻辑。

	#region Class
	public class MyInterceptor : IInterceptor
    {
    
    
        public void Intercept(IInvocation invocation)
        {
    
    
            Console.WriteLine($"intercept before");i
            // 不执行该语句 就不执行原有的方法
            invocation.Proceed();
            Console.WriteLine($"intercept after");
        }
    }

	public class T: IT
    {
    
    
        public void Write()
        {
    
    
            Console.WriteLine($"T_Write()");
        }
    }
	#endregion

    public void ConfigureContainer(ContainerBuilder builder)
    {
    
    
        #region AOP
        // 注册拦截器到容器中
        builder.RegisterType<MyInterceptor>();
        // builder.RegisterType<MyNameService>();
        builder.RegisterType<T>().As<IT>()
            // 允许属性注册
            .PropertiesAutowired()
            // 指定拦截器
            .InterceptedBy(typeof(MyInterceptor))
            // 实现接口拦截器
            // (如果用类拦截器,方法需要设置为虚方法,允许继承类重载的情况下,才可以拦截到具体方法)
            .EnableInterfaceInterceptors();
        #endregion
    }

使用时

	public void Configure(IApplicationBuilder app)
	{
    
    
		// 也可以直接在构造函数中请求 ILifetimeScope  
		ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot();
		// t 的 Attr 属性不为 null
		IT t = AutofacContainer.Resolve<IT>();
		// 可以看到方法的执行顺序
		t.Write();
	}

4) 子容器

Autofac 具备给子容器命名的特性,

    public void ConfigureContainer(ContainerBuilder builder)
    {
    
    
        #region 子容器
        builder.RegisterType<T>()
            // 将一个服务注入到特定命名为 myscope 的子容器中
            .InstancePerMatchingLifetimeScope("myscope");
        #endregion
    }

使用时

	public void Configure(IApplicationBuilder app)
	{
    
    
		// 也可以直接在构造函数中请求 ILifetimeScope  
		ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot();
        #region 子容器
        // 创建了一个叫 myscope 的子容器
        using (var myscope = AutofacContainer.BeginLifetimeScope("myscope"))
        {
    
    
            var t1= myscope.Resolve<T>();
            using (var scope = myscope.BeginLifetimeScope())
            {
    
    
                var t2= scope.Resolve<T>();
                var t3= scope.Resolve<T>();
                // 得到的都是同一个对象
                var co1 = t1 == t2; // true
                var co2 = t1 == t3; // true
            }
        }
        #endregion
	}

当我们不期望对象在根容器创建时,
又希望它在某一定范围内是单例模式的情况下,可以使用 子容器。


参考文档

07 | 用Autofac增强容器能力 - 肖伟宇

猜你喜欢

转载自blog.csdn.net/Upgrader/article/details/104228439
今日推荐