2021-03-12

在AspNetCore3.0中使用Autofac(三方容器的使用)

  1. 引入Nuget包
Autofac
Autofac.Extensions.DependencyInjection
  1. 修改Program.cs
    将默认ServiceProviderFactory指定为AutofacServiceProviderFactory
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
       .UseServiceProviderFactory(new AutofacServiceProviderFactory());
  1. 修改Startup.cs
    添加方法 ConfigureContainer
public void ConfigureContainer(ContainerBuilder builder)
{
    // 在这里添加服务注册
    builder.RegisterType<需要注册的类>();
}
  1. 配置Controller全部由Autofac创建
    默认情况下,Controller的参数会由容器创建,但Controller的创建是有AspNetCore框架实现的。要通过容器创建Controller,需要在Startup中配置一下:
services.Replace(
    ServiceDescriptor
        .Transient<IControllerActivator, ServiceBasedControllerActivator>()
);

// 或者将Controller加入到Services中,这样写上面的代码就可以省略了
services.AddControllersWithViews().AddControllersAsServices();

如果需要在Controller中使用属性注入,需要在ConfigureContainer中添加如下代码

var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
    .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
    .PropertiesAutowired();
  1. 在Controller中使用
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly TopicService _service;
    private readonly IServiceProvider _provider;

    public TopicService Service { get; set; }

    public TestController(TopicService service, IServiceProvider provider)
    {
        _service = service;
        _provider = provider;
    }

    [HttpGet("{id}")]
    public async Task<Result> GetTopics(int id)
    {            
        // 构造函数注入
        return await _service.LoadWithPosts(id);
    }

    [HttpGet("Get/{id}")]
    public async Task<Result> GetTopics2(int id)
    {
        // 属性注入
        return await Service.LoadWithPosts(id);
    }
}
  1. 使用拦截器
    添加Nuget包:Autofac.Extras.DynamicProxy
    一、定义一个拦截器类,实现IInterceptor
public class TestInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine("你正在调用方法 \"{0}\"  参数是 {1}... ",
            invocation.Method.Name,
            string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

        invocation.Proceed();
        
        Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);
    }
}

二、修改Startup的ConfigureContainer方法
注意:

1、拦截器注册要在使用拦截器的接口和类型之前
2、在类型中使用,仅virtual方法可以触发拦截器

builder.RegisterType<TestInterceptor>(); // 要先注册拦截器

builder.RegisterAssemblyTypes(typeof(Program).Assembly)
    .AsImplementedInterfaces()
    .EnableInterfaceInterceptors();

var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
    .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
    .PropertiesAutowired() // 允许属性注入
    .EnableClassInterceptors(); // 允许在Controller类上使用拦截器

三、在需要使用拦截器的类或接口上添加描述

[Intercept(typeof(TestInterceptor))]
四、Sample

在接口上添加拦截器,当调用接口的方法时,都会进入拦截器

public class LogUtil : ILogUtil
{
    public void Show(string message)
    {
        Console.WriteLine(message);
    }
}

[Intercept(typeof(TestInterceptor))]
public interface ILogUtil
{
    void Show(string message);
}
[Intercept(typeof(TestInterceptor))]
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly TopicService _service;
    private readonly IServiceProvider _provider;
    private readonly ILogUtil _log;

    public TopicService Service { get; set; }

    public TestController(TopicService service, IServiceProvider provider, ILogUtil log)
    {
        _service = service;
        _provider = provider;
        _log = log;
    }

    // 会触发拦截器
    [HttpGet("{id}")]
    public virtual async Task<Result> GetTopics(int id)
    {            
        // 构造函数注入
        return await _service.LoadWithPosts(id);
    }

    // 不会触发拦截器
    [HttpGet("Get/{id}")]
    public async Task<Result> GetTopics2(int id)
    {
        return await Service.LoadWithPosts(id);
    }

    // 会由_log触发拦截器
    [HttpGet("Get2")]
    public string GetTopics3()
    {
        _log.Show("abc");
        return "Hello World";
    }

    // 会触发拦截器2次
    [HttpGet("Get2")]
    public virtual string GetTopics4()
    {
        _log.Show("abc");
        return "Hello World";
    }
}
  1. 一个接口多个实现
    // 1、需要指定键值 是一个Object类型
    // 2、注册服务使用方法Keyed 参数为指定的键值中的值 (每一个服务的实现和键值要一一对应起来,这里不能重复)
    // 3、获取服务: 直接通过ResolveKeyed() 获取服务无,方法需要传入 指定对应的键值
    // 先获取一个IIndex,再通过IInex 索引来获取服务的实例
containerBuilder.RegisterType<TestServiceD>().Keyed<ITestServiceD>(DeviceState.TestServiceD);
containerBuilder.RegisterType<TestServiceD_One>().Keyed<ITestServiceD>(DeviceState.TestServiceD_One);
containerBuilder.RegisterType<TestServiceD_Two>().Keyed<ITestServiceD>(DeviceState.TestServiceD_Two);
containerBuilder.RegisterType<TestServiceD_Three>().Keyed<ITestServiceD>(DeviceState.TestServiceD_Three);

// 为不同的实现指定名称,这个比较简单,推荐
containerBuilder.RegisterType<TestServiceD_Three>().Named<ITestServiceD>("three");

IContainer container = containerBuilder.Build();

IIndex<DeviceState, ITestServiceD> index = container.Resolve<IIndex<DeviceState, ITestServiceD>>();

ITestServiceD testServiceD= index[DeviceState.TestServiceD];
ITestServiceD TestServiceD_One = index[DeviceState.TestServiceD_One];
ITestServiceD TestServiceD_Two = index[DeviceState.TestServiceD_Two];
ITestServiceD TestServiceD_Three = index[DeviceState.TestServiceD_Three];

// 根据名称解析
var t2 = container.ResolveNamed<ITestServiceD>("three");
Console.WriteLine("abc");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值