经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
如何将 Autofac 整合进 Net6.0 Core MVC 项目中
来源:cnblogs  作者:可均可可  时间:2023/2/28 8:52:31  对本文有异议

一、前言
    1、简而言之
        Asp.Net Core Mvc,我也用了很长一段时间了,它现在的编程模型和方式还是特别棒的,都是组件开发,什么都可以替换,当然了,您别抬杠,有些还是不能替换的。自从我们进入了跨平台开发的时代,IOC容器也成了一个不可或缺的东西了。微软为我们提供了一个默认实现,那就是 IServiceCollection,当时我们可以替换掉它,今天我就试试,替换一下,把我的一些经验也写出来,以防以后忘记,不知道去哪里找了。
        当然了,这个不是很难,也希望高手不要见笑,对于我来说,好记性不如烂笔头,好的东西我就记录下来,有使用的地方,可以直接来找。

    2、开发环境。
        我的开发环境没有发生变化,具体如下:
          操作系统:Windows10 Professional
          开发平台:Asp.Net Core Mvc 6.0
          开发语言:C#
          开发工具:Visual Studio 2022

二、操作步骤

    1、第一,我们当然要新建一个 Asp.Net Core MVC 的项目,项目都没有,其他的都是胡扯了,我项目的名称是:PatrickLiu.Autofac.MvcConcordance。
        


    2、我们为我们的项目增加相应的程序包。分别是:Autofac、Autofac.Extensions.DependencyInjection、Autofac.Extras.DynamicProxy,Castle.Core
        1】、Autofac 提供最基础、最核心的功能。
        2】、Autofac.Extensions.DependencyInjection 提供和 Asp.Net Core MVC 集成的接口。
        3】、Autofac.Extras.DynamicProxy 提供对AOP的支持,通过动态代理实现。
        4】、Castle.Core 实现针对 Core 版本的支持,也是支持 AOP 的必需组件。

        

    3、这部分是重点,在 Program 程序中配置。具体代码在里面,很简单,就不多说了。

  1. 1 using Autofac;
  2. 2 using Autofac.Extensions.DependencyInjection;
  3. 3 using Autofac.Extras.DynamicProxy;
  4. 4 using Castle.DynamicProxy;
  5. 5 using Microsoft.AspNetCore.Mvc;
  6. 6 using Microsoft.AspNetCore.Mvc.Controllers;
  7. 7 using PatrickLiu.Autofac.Contracts;
  8. 8 using PatrickLiu.Autofac.Extensions;
  9. 9 using PatrickLiu.Autofac.Extensions.Aops;
  10. 10 using PatrickLiu.Autofac.Models;
  11. 11
  12. 12 var builder = WebApplication.CreateBuilder(args);
  13. 13 builder.Services.AddControllersWithViews();
  14. 14
  15. 15 #region 整合 Autofac
  16. 16
  17. 17 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
  18. 18
  19. 19 builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
  20. 20 {
  21. 21 builder.RegisterType<ChiesePerson>().As<IPerson>();
  22. 22 builder.RegisterType<SinglePerson>();
  23. 23
  24. 24 #region 服务类型支持属性注入,红色表示是对属性注入的支持,哪个类型需要属性注入,在注册的时候使用 PropertiesAutowired()方法,里面参数是属性选择器。
  25. 25
  26. 26 builder.RegisterType<PropertyPerson>().As<IPropertyPerson>().PropertiesAutowired(new CustomPropertySelector());
  27. 27 builder.RegisterType<PropertyTwoPerson>().As<IPropertyTwoPerson>();
  28. 28 builder.RegisterType<PropertyThreePerson>().As<IPropertyThreePerson>();
  29. 29 builder.RegisterType<SinglePerson>();
  30. 30
  31. 31 #endregion
  32. 32
  33. 33 #region AOP支持,红色标注的是关键实现。
  34. 34
  35. 35 builder.RegisterType<AOPPerson>().As<IAOPPerson>().EnableInterfaceInterceptors();
  36. 36 builder.RegisterType<AOPClassPerson>().As<IAOPClassPerson>().EnableClassInterceptors(new ProxyGenerationOptions()
  37. 37 {
  38. 38 Selector = new CustomInterceptorSelector()
  39. 39 });
  40. 40 builder.RegisterType<AOPCachePerson>().As<IAOPCachePerson>().EnableClassInterceptors();
  41. 41
  42. 42 builder.RegisterType<CustomClassInterceptor>();
  43. 43 builder.RegisterType<CustomInterfaceInterceptor>();
  44. 44 builder.RegisterType<CustomCacheInterceptor>();
  45. 45
  46. 46 #endregion
  47. 47
  48. 48 #region 单接口多实例
  49. 49
  50. 50 builder.RegisterType<MultiPerson>().Keyed<IMultiPerson>("MultiPerson");
  51. 51 builder.RegisterType<MultiTwoPerson>().Keyed<IMultiPerson>("MultiTwoPerson");
  52. 52 builder.RegisterType<MultiThreePerson>().Keyed<IMultiPerson>("MultiThreePerson");
  53. 53
  54. 54 #endregion
  55. 55
  56. 56 #region 让控制器支持属性注入
  57. 57
  58. 58 var controllerBaseType = typeof(ControllerBase);
  59. 59 builder.RegisterAssemblyTypes(typeof(Program).Assembly)
  60. 60 .Where(t => controllerBaseType.IsAssignableFrom(t) && controllerBaseType != t)
  61. 61 .PropertiesAutowired(new CustomPropertySelector());
  62. 62
  63. 63 builder.RegisterType<ServiceBasedControllerActivator>().As<IControllerActivator>();
  64. 64
  65. 65 #endregion
  66. 66 });
  67. 67
  68. 68 #region 支持 Autofac 属性注入,该方法可以使用,也可以不使用。作用是我们的控制器要使用 Autofac 容器来创建,替换原始的 Controller 激活器。
  69. 69
  70. 70 //builder.Services.AddTransient<IControllerActivator, ServiceBasedControllerActivator>();
  71. 71 //builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
  72. 72
  73. 73 #endregion
  74. 74
  75. 75 #endregion
  76. 76
  77. 77 var app = builder.Build();
  78. 78
  79. 79 app.UseStaticFiles();
  80. 80
  81. 81 app.UseRouting();
  82. 82
  83. 83 app.MapControllerRoute("default", "{controller=AOP}/{action=index}/{id?}");
  84. 84
  85. 85 app.Run();


    4、Autofac 支持属性注入,默认是所有属性的类型如果是注册的服务类型,就会全部赋值,但是,我们也可以实现 IPropertySelector 接口,自定义哪个属性需要注入。

  1. 1 using Autofac.Core;
  2. 2 using System.Reflection;
  3. 3
  4. 4 namespace PatrickLiu.Autofac.Extensions
  5. 5 {
  6. 6 public sealed class CustomPropertySelector : IPropertySelector
  7. 7 {
  8. 8 public bool InjectProperty(PropertyInfo propertyInfo, object instance)
  9. 9 {
  10. 10 return propertyInfo.IsDefined(typeof(CustomPropertySelectorAttribute), false);
  11. 11 }
  12. 12 }
  13. 13 }

      有了选择器,我们也需要定义特性(Attribute),标注属性(Property)就可以。

  1. 1 namespace PatrickLiu.Autofac.Extensions
  2. 2 {
  3. 3 /// <summary>
  4. 4 ///
  5. 5 /// </summary>
  6. 6 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
  7. 7 public sealed class CustomPropertySelectorAttribute : Attribute
  8. 8 {
  9. 9 }
  10. 10 }

       有了这两个,我们在把我们自定义的属性选择器 CustomPropertySelector 作为参数,传递给 PropertiesAutowired(new CustomPropertySelector())方法,就完成操作了。
      

  1. 1 using Microsoft.AspNetCore.Mvc;
  2. 2 using PatrickLiu.Autofac.Contracts;
  3. 3 using PatrickLiu.Autofac.Extensions;
  4. 4 using PatrickLiu.Autofac.Models;
  5. 5
  6. 6 namespace PatrickLiu.Autofac.MvcConcordance.Controllers
  7. 7 {
  8. 8 /// <summary>
  9. 9 ///
  10. 10 /// </summary>
  11. 11 public class PropertyInjectionController : Controller
  12. 12 {
  13. 13 private readonly IPropertyPerson _propertyPerson;
  14. 14
  15. 15 /// <summary>
  16. 16 ///
  17. 17 /// </summary>
  18. 18 /// <param name="propertyPerson"></param>
  19. 19 public PropertyInjectionController(IPropertyPerson propertyPerson)
  20. 20 {
  21. 21 _propertyPerson = propertyPerson;
  22. 22 }
  23. 23
  24. 24 /// <summary>
  25. 25 /// 这里就是控制器的属性,需要自动初始化。
  26. 26 /// </summary>
  27. 27 [CustomPropertySelector]
  28. 28 public SinglePerson? SinglePerson { get; set; }
  29. 29
  30. 30 /// <summary>
  31. 31 ///
  32. 32 /// </summary>
  33. 33 /// <returns></returns>
  34. 34 public IActionResult Index()
  35. 35 {
  36. 36 _propertyPerson.Process();
  37. 37
  38. 38 return View();
  39. 39 }
  40. 40 }
  41. 41 }


    5、Autofac 支持两种类型 AOP,分别是:EnableClassInterceptors 和 EnableInterfaceInterceptors ,类拦截器必须使用 [Intercept(typeof(CustomClassInterceptor))]标注需要实现 AOP 的实现类上,如果是接口拦截器,就必须将 [Intercept(typeof(CustomInterfaceInterceptor))] 标注在需要实现 AOP 的接口类型上。
        1】、EnableClassInterceptors:类拦截器,它的方法必须是 virtual 虚方法,才可以支持 AOP。
        2】、EnableInterfaceInterceptors:接口拦截器,没有相关限制,该接口的实现类的方法都会实现 AOP。
        这就是接口拦截器。

  1. 1 using Autofac.Extras.DynamicProxy;
  2. 2 using PatrickLiu.Autofac.Extensions.Aops;
  3. 3
  4. 4 namespace PatrickLiu.Autofac.Contracts
  5. 5 {
  6. 6 /// <summary>
  7. 7 ///
  8. 8 /// </summary>
  9. 9 [Intercept(typeof(CustomInterfaceInterceptor))]
  10. 10 public interface IAOPPerson
  11. 11 {
  12. 12 /// <summary>
  13. 13 ///
  14. 14 /// </summary>
  15. 15 void Process();
  16. 16
  17. 17 /// <summary>
  18. 18 ///
  19. 19 /// </summary>
  20. 20 void ProcessTwo();
  21. 21
  22. 22 /// <summary>
  23. 23 ///
  24. 24 /// </summary>
  25. 25 void ProcessThree();
  26. 26 }
  27. 27 }

        以下是类拦截器。

  1. 1 using Autofac.Extras.DynamicProxy;
  2. 2 using PatrickLiu.Autofac.Contracts;
  3. 3 using PatrickLiu.Autofac.Extensions.Aops;
  4. 4
  5. 5 namespace PatrickLiu.Autofac.Models
  6. 6 {
  7. 7 /// <summary>
  8. 8 ///
  9. 9 /// </summary>
  10. 10 [Intercept(typeof(CustomClassInterceptor))]
  11. 11 public class AOPClassPerson : IAOPClassPerson
  12. 12 {
  13. 13 /// <summary>
  14. 14 ///
  15. 15 /// </summary>
  16. 16 public virtual void ProcessAOP()
  17. 17 {
  18. 18 Console.WriteLine("AOPClassPerson.ProcessAOP()");
  19. 19 }
  20. 20
  21. 21 /// <summary>
  22. 22 ///
  23. 23 /// </summary>
  24. 24 public void Process()
  25. 25 {
  26. 26 Console.WriteLine("AOPClassPerson.Process()");
  27. 27 }
  28. 28 }
  29. 29 }

    6、我们要自定义我们的拦截器,然后再标注的类型标注 [Intercept(typeof(自定义拦截器))],就可以使用,我分别定义了两个拦截器,一个用于类,一个用于接口,其实没有本质区别,实现的接口都是一样的,该接口就是:IInterceptor。

  1. 1 using Castle.DynamicProxy;
  2. 2
  3. 3 namespace PatrickLiu.Autofac.Extensions.Aops
  4. 4 {
  5. 5 /// <summary>
  6. 6 /// 类级别的拦截器,标注在要实现AOP功能的类型上。
  7. 7 /// </summary>
  8. 8 public sealed class CustomClassInterceptor : IInterceptor
  9. 9 {
  10. 10 /// <summary>
  11. 11 ///
  12. 12 /// </summary>
  13. 13 /// <param name="invocation"></param>
  14. 14 public void Intercept(IInvocation invocation)
  15. 15 {
  16. 16 {
  17. 17 Console.WriteLine("CustomClassInterceptor.Before");
  18. 18 }
  19. 19 invocation.Proceed();
  20. 20 {
  21. 21 Console.WriteLine("CustomClassInterceptor.After");
  22. 22 }
  23. 23 }
  24. 24 }
  25. 25 }
  1. 1 using Castle.DynamicProxy;
  2. 2
  3. 3 namespace PatrickLiu.Autofac.Extensions.Aops
  4. 4 {
  5. 5 /// <summary>
  6. 6 /// 接口级别的拦截器,标注在要实现AOP功能的接口类型上。
  7. 7 /// </summary>
  8. 8 public sealed class CustomInterfaceInterceptor : IInterceptor
  9. 9 {
  10. 10 /// <summary>
  11. 11 ///
  12. 12 /// </summary>
  13. 13 /// <param name="invocation"></param>
  14. 14 public void Intercept(IInvocation invocation)
  15. 15 {
  16. 16 {
  17. 17 Console.WriteLine("CustomInterfaceInterceptor.Before");
  18. 18 }
  19. 19 invocation.Proceed();
  20. 20 {
  21. 21 Console.WriteLine("CustomInterfaceInterceptor.After");
  22. 22 }
  23. 23 }
  24. 24 }
  25. 25 }


    7、当然,我们也可以不标注 [Intercept(typeof(自定义拦截器))],我们可以实现 IInterceptorSelector 接口,实现自定义使用哪些拦截器。代码如下:
       

  1. 1 using Castle.DynamicProxy;
  2. 2 using System.Reflection;
  3. 3
  4. 4 namespace PatrickLiu.Autofac.Extensions.Aops
  5. 5 {
  6. 6 /// <summary>
  7. 7 ///
  8. 8 /// </summary>
  9. 9 public class CustomInterceptorSelector : IInterceptorSelector
  10. 10 {
  11. 11 /// <summary>
  12. 12 ///
  13. 13 /// </summary>
  14. 14 /// <param name="type"></param>
  15. 15 /// <param name="method"></param>
  16. 16 /// <param name="interceptors">如果类型有标注拦截器,这里会获取所有拦截器。</param>
  17. 17 /// <returns></returns>
  18. 18 public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors)
  19. 19 {
  20. 20 IList<IInterceptor> interceptorsList = new List<IInterceptor>();
  21. 21 interceptorsList.Add(new CustomInterfaceInterceptor());
  22. 22        在这个方法里面,我们可以过滤拦截器,想是哪个起作用哪个就起作用。返回的拦截器,就是起作用的拦截器。
  23. 23 return interceptorsList.ToArray();
  24. 24 }
  25. 25 }
  26. 26 }

       我们可以选择拦截器,也需要在Program 里体现,builder.RegisterType<AOPClassPerson>().As<IAOPClassPerson>().EnableClassInterceptors(new ProxyGenerationOptions()  {     Selector = new CustomInterceptorSelector()   });

    8、Autofac 默认支持构造函数注入,如果有多个构造函数,如果构造函数的参数都是需要注入的服务类型,默认选择依赖注册服务参数最多的构造函数会被执行。当然我们也可以选择指定的构造函数来初始化类型实例,该方法就是 .UsingConstructor(typeof(参数类型))。
      

  1. builder.RegisterType<ChiesePerson>().As<IPerson>().UsingConstructor(typeof(int));
  1. 1 using Autofac;
  2. 2 using Microsoft.AspNetCore.Mvc;
  3. 3 using PatrickLiu.Autofac.Contracts;
  4. 4 using PatrickLiu.Autofac.Models;
  5. 5
  6. 6 namespace PatrickLiu.Autofac.MvcConcordance.Controllers
  7. 7 {
  8. 8 /// <summary>
  9. 9 ///
  10. 10 /// </summary>
  11. 11 public class HomeController : Controller
  12. 12 {
  13. 13 private readonly IPerson _person;
  14. 14 private readonly IServiceProvider _serviceProvider;
  15. 15 private readonly IComponentContext _componentContext;
  16. 16
  17. 17 /// <summary>
  18. 18 ///
  19. 19 /// </summary>
  20. 20 /// <param name="person"></param>
  21. 21 /// <param name="serviceProvider">服务提供器,类型是 AutofacServiceProvider,获取类型。</param>
  22. 22 /// <param name="componentContext">autofac 的上下文对象,可以获取容器中的服务。</param>
  23. 23 public HomeController(IPerson person, IServiceProvider serviceProvider, IComponentContext componentContext)
  24. 24 {
  25. 25 _person = person;
  26. 26 _serviceProvider = serviceProvider;
  27. 27 _componentContext = componentContext;
  28. 28 }
  29. 29
  30. 30 public IActionResult Index()
  31. 31 {
  32. 32 _person.Eat("炸酱面");
  33. 33
  34. 34 var single=_serviceProvider.GetService<SinglePerson>();
  35. 35 single!.Eat("残羹冷炙");
  36. 36
  37. 37 var singleTwo=_componentContext.Resolve<SinglePerson>();
  38. 38 singleTwo.Eat("残羹剩饭");
  39. 39
  40. 40 return View();
  41. 41 }
  42. 42 }
  43. 43 }


三、结束语
    平台本身提供了自己的容器实现,当然,我们也可以替换它,使用其他的 IOC容器。不学不知道,一学吓一跳,东西还有很多不知道了。平凡的我,只能继续努力,苍天不负有心人,努力就会有回报。不忘初心,继续努力吧。
    

原文链接:https://www.cnblogs.com/PatrickLiu/p/17147826.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号