如何将 Autofac 整合进 Net6.0 Core MVC 项目中

如何,autofac,整合,net6,core,mvc,项目 · 浏览次数 : 481

小编点评

# Custom Interceptor Selector ```C# using Castle.DynamicProxy; using System.Reflection; using PatrickLiu.Autofac.Extensions.Aops; using PatrickLiu.Autofac.Models; namespace PatrickLiu.Autofac.MvcConcordance.Controllers { public class HomeController : Controller12 { private readonly IPerson _person; private readonly IServiceProvider _serviceProvider; private readonly IComponentContext _componentContext; public HomeController(IPerson person, IServiceProvider serviceProvider, IComponentContext componentContext) { _person = person; _serviceProvider = serviceProvider; _componentContext = componentContext; } public IActionResult Index() { _person.Eat("炸酱面"); var single = _serviceProvider.GetService(); single!.Eat("残羹冷炙"); var singleTwo = _componentContext.Resolve(); singleTwo.Eat("残羹剩饭"); return View(); } } } ``` # Usage ```C# builder.RegisterType().As().UsingConstructor(typeof(int)); ``` # Explanation 1. Custom Interceptor Selector 是一个接口,用于选择拦截器。 2. 实现接口的 SelectInterceptors 方法,返回拦截器数组。 3. 在控制器中,使用 IComponentContext 获取组件上下文。 4. 在控制器中,使用 IServiceProvider 获取服务。 5. 在使用 IServiceProvider 获取服务的时候,可以指定选择哪个构造函数。 6. 使用 IComponentContext 的 Resolve 方法获取依赖注入的服务。

正文

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


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

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

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

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

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

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


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

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

        以下是类拦截器。

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

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

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


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

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

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

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

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


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

与如何将 Autofac 整合进 Net6.0 Core MVC 项目中相似的内容:

如何将 Autofac 整合进 Net6.0 Core MVC 项目中

一、前言 1、简而言之 Asp.Net Core Mvc,我也用了很长一段时间了,它现在的编程模型和方式还是特别棒的,都是组件开发,什么都可以替换,当然了,您别抬杠,有些还是不能替换的。自从我们进入了跨平台开发的时代,IOC容器也成了一个不可或缺的东西了。微软为我们提供了一个默认实现,那就是 ISe

如何将文本转换为向量?(方法三)

​ 文本转换为向量有多种方式: 方法一:通过模型服务灵积DashScope将文本转换为向量(推荐) 方法二:通过ModelScope魔搭社区中的文本向量开源模型将文本转换为向量 方法三:通过Jina Embeddings v2模型将文本转换为向量 方法四:通过百川智能向量化模型将文本转换为向量 本文

如何将 Win10 企业版转换为专业版

有时候,我们需要将 Windows 10 企业版转换为专业版。这种情况可能发生在您购买了预装企业版的电脑,但实际上只需要专业版的功能。本文将介绍如何简单地将 Windows 10 企业版转换为专业版。 准备工作 下载转换所需的安装文件。您可以从以下链接获取: 链接: https://pan.baid

如何将Tiff文件切成瓦片( GDAL切片) gdal2tile - 基于C++语言开发

准备资料 1. 一张wgs84投影的大tiff文件,建议初学者使用一张全球 2048 * 1024 / 4096 * 2048 的完整数据(有助于观察验证) 2. 准备C++开发环境,配置好gdal (笔者使用的环境是 vs2022 + gdal-2.3.0) c++ 开发环境 3. 建立一个测试工

如何将WebAssembly优化到1MB?

Blazor WebAssembly加载优化方案 对于Blazor WebAssembly加载方案的优化是针对于WebAssembly首次加载,由于BlazorWebAssembly是在首次加载的时候会将.NET Core的所有程序集都会加载到浏览器中,并且在使用的时候可能引用了很多第三方的dll,

如何将c#在线编辑器嵌入自己项目

如何将c#在线编辑器嵌入自己项目 首先我们需要介绍一下这个在线编辑器,当前的在线编辑器支持c#的代码编译运行,并且无需后台服务,基于WebAssembly实现的在浏览器端去执行我们的c#代码,基于Roslyn提供的Api封装一套简单的编译,并且封装了js的支持,让嵌入的方式更简单。 使用现有项目嵌入

如何将现有的`Blazor`项目的主题切换写的更好看?

# 如何将现有的`Blazor`项目的主题切换写的更好看? 在现有的系统当中,我们的主题切换会比较生硬,下面我们将基于Masa Blazor实现好看的扩散主题切换的样式效果。 ## 安装MASA.Template ```sh dotnet new install MASA.Template ```

如何将BI 工具与业务系统进行单点登录对接,实现用户权限通用

本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 首先来看下两套系统的用户体系功能,左边是BI 工具,右边是业务系统,需要实现用户权限对接和打通: 单点登录体系及用户场景 • 场景1. 用户登录Wyn BI页面使用第三

如何将使用中的域名平滑迁移到京东云?(以原域名注册、域名解析都在万网为例)

首先要了解的是,1、域名注册 2、域名解析,是两个独立的产品。一般情况下,域名服务商(万网、新网等)会提供一站式服务,既提供“域名购买注册”,又提供“域名解析服务”。 但实际上,域名和域名解析是可以分开部署的,域名服务商也支持相关的分离设置。比如:域名在万网进行管理,域名解析可以指向其他域名服务商的NS服务器。更进一步,域名也可以从原域名服务商(万网),迁移到新的域名服务商(新网)。

一台不容错过的Java单元测试代码“永动机”

如何将失误降到最低?我们期望能打造一台生产Java单元测试代码的“永动机”,源源不断地为开发者生产代码,辅助大家高效地做好单元测试,节省精力能投入到更多的业务创新中去。