当前位置:   article > 正文

在AspNetCore3.0中使用Autofac

services.addcontrollerswithviews().addcontrollersasservices

1. 引入Nuget包

  1. Autofac
  2. Autofac.Extensions.DependencyInjection

2. 修改Program.cs

将默认ServiceProviderFactory指定为AutofacServiceProviderFactory

  1. public static IHostBuilder CreateHostBuilder(string[] args) =>
  2. Host.CreateDefaultBuilder(args)
  3. .ConfigureWebHostDefaults(webBuilder =>
  4. {
  5. webBuilder.UseStartup<Startup>();
  6. })
  7. .UseServiceProviderFactory(new AutofacServiceProviderFactory());

3. 修改Startup.cs

添加方法 ConfigureContainer

  1. public void ConfigureContainer(ContainerBuilder builder)
  2. {
  3. // 在这里添加服务注册
  4. builder.RegisterType<TopicService>();
  5. }

4. 配置Controller全部由Autofac创建

默认情况下,Controller的参数会由容器创建,但Controller的创建是有AspNetCore框架实现的。要通过容器创建Controller,需要在Startup中配置一下:

  1. services.Replace(
  2. ServiceDescriptor
  3. .Transient<IControllerActivator, ServiceBasedControllerActivator>()
  4. );
  5. // 或者将Controller加入到Services中,这样写上面的代码就可以省略了
  6. services.AddControllersWithViews().AddControllersAsServices();

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

  1. var controllerBaseType = typeof(ControllerBase);
  2. builder.RegisterAssemblyTypes(typeof(Program).Assembly)
  3. .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
  4. .PropertiesAutowired();

5. 在Controller中使用

  1. [Route("api/[controller]")]
  2. [ApiController]
  3. public class TestController : ControllerBase
  4. {
  5. private readonly TopicService _service;
  6. private readonly IServiceProvider _provider;
  7. public TopicService Service { get; set; }
  8. public TestController(TopicService service, IServiceProvider provider)
  9. {
  10. _service = service;
  11. _provider = provider;
  12. }
  13. [HttpGet("{id}")]
  14. public async Task<Result> GetTopics(int id)
  15. {
  16. // 构造函数注入
  17. return await _service.LoadWithPosts(id);
  18. }
  19. [HttpGet("Get/{id}")]
  20. public async Task<Result> GetTopics2(int id)
  21. {
  22. // 属性注入
  23. return await Service.LoadWithPosts(id);
  24. }
  25. }

6. 使用拦截器

添加Nuget包:Autofac.Extras.DynamicProxy
一、定义一个拦截器类,实现IInterceptor
  1. public class TestInterceptor : IInterceptor
  2. {
  3. public void Intercept(IInvocation invocation)
  4. {
  5. Console.WriteLine("你正在调用方法 \"{0}\" 参数是 {1}... ",
  6. invocation.Method.Name,
  7. string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));
  8. invocation.Proceed();
  9. Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);
  10. }
  11. }
二、修改StartupConfigureContainer方法

注意:

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

  1. builder.RegisterType<TestInterceptor>(); // 要先注册拦截器
  2. builder.RegisterAssemblyTypes(typeof(Program).Assembly)
  3. .AsImplementedInterfaces()
  4. .EnableInterfaceInterceptors();
  5. var controllerBaseType = typeof(ControllerBase);
  6. builder.RegisterAssemblyTypes(typeof(Program).Assembly)
  7. .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
  8. .PropertiesAutowired() // 允许属性注入
  9. .EnableClassInterceptors(); // 允许在Controller类上使用拦截器
三、在需要使用拦截器的类或接口上添加描述
[Intercept(typeof(TestInterceptor))]
四、Sample

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

  1. public class LogUtil : ILogUtil
  2. {
  3. public void Show(string message)
  4. {
  5. Console.WriteLine(message);
  6. }
  7. }
  8. [Intercept(typeof(TestInterceptor))]
  9. public interface ILogUtil
  10. {
  11. void Show(string message);
  12. }

在Controller上使用拦截器

  1. [Intercept(typeof(TestInterceptor))]
  2. [Route("api/[controller]")]
  3. [ApiController]
  4. public class TestController : ControllerBase
  5. {
  6. private readonly TopicService _service;
  7. private readonly IServiceProvider _provider;
  8. private readonly ILogUtil _log;
  9. public TopicService Service { get; set; }
  10. public TestController(TopicService service, IServiceProvider provider, ILogUtil log)
  11. {
  12. _service = service;
  13. _provider = provider;
  14. _log = log;
  15. }
  16. // 会触发拦截器
  17. [HttpGet("{id}")]
  18. public virtual async Task<Result> GetTopics(int id)
  19. {
  20. // 构造函数注入
  21. return await _service.LoadWithPosts(id);
  22. }
  23. // 不会触发拦截器
  24. [HttpGet("Get/{id}")]
  25. public async Task<Result> GetTopics2(int id)
  26. {
  27. return await Service.LoadWithPosts(id);
  28. }
  29. // 会由_log触发拦截器
  30. [HttpGet("Get2")]
  31. public string GetTopics3()
  32. {
  33. _log.Show("abc");
  34. return "Hello World";
  35. }
  36. // 会触发拦截器2次
  37. [HttpGet("Get2")]
  38. public virtual string GetTopics4()
  39. {
  40. _log.Show("abc");
  41. return "Hello World";
  42. }
  43. }

7. 一个接口多个实现

  1. // 1、需要指定键值 是一个Object类型
  2. // 2、注册服务使用方法Keyed 参数为指定的键值中的值 (每一个服务的实现和键值要一一对应起来,这里不能重复)
  3. // 3、获取服务: 直接通过ResolveKeyed() 获取服务无,方法需要传入 指定对应的键值
  4. // 先获取一个IIndex,再通过IInex 索引来获取服务的实例
  5. containerBuilder.RegisterType<TestServiceD>().Keyed<ITestServiceD>(DeviceState.TestServiceD);
  6. containerBuilder.RegisterType<TestServiceD_One>().Keyed<ITestServiceD>(DeviceState.TestServiceD_One);
  7. containerBuilder.RegisterType<TestServiceD_Two>().Keyed<ITestServiceD>(DeviceState.TestServiceD_Two);
  8. containerBuilder.RegisterType<TestServiceD_Three>().Keyed<ITestServiceD>(DeviceState.TestServiceD_Three);
  9. // 为不同的实现指定名称,这个比较简单,推荐
  10. containerBuilder.RegisterType<TestServiceD_Three>().Named<ITestServiceD>("three");
  11. IContainer container = containerBuilder.Build();
  12. IIndex<DeviceState, ITestServiceD> index = container.Resolve<IIndex<DeviceState, ITestServiceD>>();
  13. ITestServiceD testServiceD= index[DeviceState.TestServiceD];
  14. ITestServiceD TestServiceD_One = index[DeviceState.TestServiceD_One];
  15. ITestServiceD TestServiceD_Two = index[DeviceState.TestServiceD_Two];
  16. ITestServiceD TestServiceD_Three = index[DeviceState.TestServiceD_Three];
  17. // 根据名称解析
  18. var t2 = container.ResolveNamed<ITestServiceD>("three");
  19. Console.WriteLine("abc");
上面的做法在客户端或者之前的MVC项目中可以这样用。但在AspNetCore3.0中,我们似乎根本拿不到IContainer,所以不能手动Resolve指定的实现,下面是我自己摸索的办法:
  1. public interface ITestUtil
  2. {
  3. void Show(string content);
  4. }
  5. public class TestUtil1 : ITestUtil
  6. {
  7. public void Show(string content)
  8. {
  9. Console.WriteLine("TestUtil1:" + content);
  10. }
  11. }
  12. public class TestUtil2 : ITestUtil
  13. {
  14. public void Show(string content)
  15. {
  16. Console.WriteLine($"TestUtil2:{content}");
  17. }
  18. }

别忘了在Startup中注册服务

  1. builder.RegisterType<TestUtil1>().As<ITestUtil>();
  2. builder.RegisterType<TestUtil2>().As<ITestUtil>();
  3. // 或者这样做,如果程序级中的类型实现了某个接口,
  4. // 会自动把该类型注册为接口的实现,
  5. // 这个方法比较狠,个人感觉还是慎用的好
  6. builder.RegisterAssemblyTypes(this.GetType().Assembly)
  7. .AsImplementedInterfaces()
  8. .PropertiesAutowired();
  1. // 默认情况下,构造函数注入和属性注入的结果都是最后注册的那个实现,
  2. // 也就是TestUtil2
  3. private readonly ITestUtil _util;
  4. public HomeController(ITestUtil util, IServiceProvider provider)
  5. {
  6. _util = util;
  7. // 如果知道注册的顺序,可以用这种方式,
  8. // 第一个注册是TestUtil1,所以这里返回TestUtil1
  9. var util1 = provider.GetServices<ITestUtil>().ElementAtOrDefault(0);
  10. util1?.Show("指定注册为ITestUtil的第一个实现");
  11. // 一般情况下用这种方式,指定成具体的类型 TestUtil1
  12. var utilFirst = provider.GetServices<ITestUtil>()
  13. .SingleOrDefault(t => t.GetType() == typeof(TestUtil1));
  14. util1?.Show("指定名称为TestUtil的实现");
  15. }

转载于:https://www.cnblogs.com/diwu0510/p/11562248.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/141292
推荐阅读
  

闽ICP备14008679号