如何将 Autofac 整合进 Net6.0 Core MVC 项目中
一、前言
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 项目中的更多相关文章
- .Net Core .Net Core V1.0 创建MVC项目
.Net Core V1.0 创建MVC项目 创建MVC项目有两种方式: 一.创建Web项目:(有太多没用的东西要去删太麻烦) 2.项目目录结构: 此种方法要注意的是,会创建好多个json文件,下面就 ...
- ASP.NET CORE MVC 2.0 如何在Filter中使用依赖注入来读取AppSettings,及.NET Core控制台项目中读取AppSettings
问: ASP.NET CORE MVC 如何在Filter中使用依赖注入来读取AppSettings 答: Dependency injection is possible in filters as ...
- C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求
C# 动态创建SQL数据库(二) 使用Entity Framework 创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...
- Docker 部署Dotnet Core MVC项目
原文:Docker 部署Dotnet Core MVC项目 1.dotnet core创建项目 dotnet new mvc -o myweb cd myweb 然后就是业务代码的编辑,增删改查乱七八 ...
- .net core mvc项目部署nginx报错一直显示404错误
遇到一个奇怪的问题,.net core mvc 项目部署到nginx上面,系统是linux,controller明明抛出500错误,但页面一直显示是404. 解决如下: 1.修改Startup.cs, ...
- 使用EF Core+CodeFirst建立ASP.NET Core MVC项目
本篇随笔介绍如何使用.NET Core+EF Core创建Web应用程序 首先借用官网的话简单介绍一下ASP.NET Core ASP.NET Core 是一个跨平台的高性能开源框架,用于生成基于云且 ...
- 新建 ASP.NET Core MVC 项目 -- Hello World!
一.创建一个空项目 请查看 新建 .NET Core 项目 -- Hello World! 一节,新建一个项目: 二.添加引用并修改配置为 MVC 修改 .vscode\launch.json 文件 ...
- 如何在启用JWT Token授权的.NET Core WebApi项目中下载文件
背景 前几天,做项目的时候遇到一个文件下载的问题.当前系统是一个前后端分离的项目,前端是一个AngularJs项目, 后端是一个.NET Core WebApi项目.后端的Api项目使用了Jwt To ...
- 解决.NET Core MVC 视图中的中文被html编码的问题
在 .net core mvc 视图输出 变量的时候 默认使用的是 UnicodeRanges.BasicLatin 进行的编码 所以 输出中文后在查看源码的时候是进过编码了的 . 解决方案 在 ...
- 在.net core web 项目中使用Nlog记录日志
第1步,添加NLog.Web.AspNetCore包引用 方法1 在项目上右击“依赖项”---“管理Nuget程序包(N)…”,然后在浏览对话框中输入“NLog.Web.AspNetCore”查找包, ...
随机推荐
- [论文阅读] 颜色迁移-Linear Monge-Kantorovitch(MKL)
[论文阅读] 颜色迁移-Linear Monge-Kantorovitch(MKL) 文章: The Linear Monge-Kantorovitch Linear Colour Mapping f ...
- 【Java SE进阶】Day10 缓冲流、转换流、序列化流 、打印流
一.缓冲流 1.概述 比普通流更强大的IO流,可以增加读写的效率 组成 缓冲输入流:BufferedInputStream.BufferedReader 缓冲输出流:BufferedOutputStr ...
- 【大数据面试】【框架】Zookeeper作用、半数机制、命令、安装台数
〇.作用 存储和管理数据 Zookeeper=文件系统+通知机制 树形结构,每个节点被称为一个Znode(1MB) 一.半数机制 1.注意 安装奇数台(4台) 二.常用命令 ls get create ...
- 【vue3】element-plus,Checkbox-Group多选框之绑定选中数据不选中问题
今天记录一下在新项目vue3中,使用的element-plus组价库遇到的一个问题!场景如下:有一个表格的column绑定的数组对象,我需要对表格的头部实现动态可配置显示表格列,由于绑定的column ...
- jQuery使用 前端框架Bootstrap
目录 jQuery查找标签 1.基本选择器 2.组合选择器 3.后代选择器 4.属性选择器 5.基本筛选器 7.筛选器方法 链式操作的本质 操作标签 1.class操作 2.位置操作 3.文本操作 4 ...
- SQL注入问题、视图、触发器、事物、存储过程、函数、流程控制、索引相关概念、索引数据结构、慢查询优化、
目录 SQL注入问题 视图 触发器 事物 存储过程 函数 流程控制 索引相关概念 索引数据结构 慢查询优化 测试装备 联合索引 全文检索 插入数据 更新数据 删除数据 主键 外键 重命名表 事物 安全 ...
- 软件工程大作业——“你帮我助”软件开发v2.0
项目简介 在疫情管控期间,很多物资由于信息不对称,不能达成资源的有效分配,尽管这样的事件已经基本不会在新冠疫情的场景中出现,但是开发出一个物品交换的公开信息平台在任何一个社区中都是有必要的,这是构建完 ...
- openEuler 部署Kubernetes(K8s)集群
前言 由于工作原因需要使用 openEuler,openEuler官方文档部署K8s集群比较复杂,并且网上相关资料较少,本文是通过实践与测试整理的 openEuler 22.03 部署 Kuberne ...
- 官网下载CentOS系统镜像过程
想学习CentOS系统,但是不知道镜像去哪里搞,随便去个第三方发现要么要注册,要么各种广告病毒,或者好不容易找到官网,不仅全英文,有些专业术语也不懂,本文说明官网下载自己想要的CentOS镜像整个流程 ...
- 我的基于 JamStack 的新博客
概述 今天心血来潮,介绍一下我的新博客站点 -- https://EWhisper.cn. 我是做基础平台 PaaS 运维和架构的,挺喜欢把工作中学到的新知识写下来.记笔记,突然有一天就抱着「资源共享 ...