在AspNetCore3.0中使用Autofac
1. 引入Nuget包
Autofac
Autofac.Extensions.DependencyInjection
2. 修改Program.cs
将默认ServiceProviderFactory
指定为AutofacServiceProviderFactory
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
3. 修改Startup.cs
添加方法 ConfigureContainer
public void ConfigureContainer(ContainerBuilder builder)
{
// 在这里添加服务注册
builder.RegisterType<TopicService>();
}
4. 配置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();
5. 在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);
}
}
6. 使用拦截器
添加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);
}
在Controller上使用拦截器
[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";
}
}
7. 一个接口多个实现
// 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");
上面的做法在客户端或者之前的MVC项目中可以这样用。但在AspNetCore3.0中,我们似乎根本拿不到IContainer,所以不能手动Resolve指定的实现(请看下方的补充),下面是我自己摸索的办法:
public interface ITestUtil
{
void Show(string content);
}
public class TestUtil1 : ITestUtil
{
public void Show(string content)
{
Console.WriteLine("TestUtil1:" + content);
}
}
public class TestUtil2 : ITestUtil
{
public void Show(string content)
{
Console.WriteLine($"TestUtil2:{content}");
}
}
别忘了在Startup中注册服务
builder.RegisterType<TestUtil1>().As<ITestUtil>();
builder.RegisterType<TestUtil2>().As<ITestUtil>();
// 或者这样做,如果程序级中的类型实现了某个接口,
// 会自动把该类型注册为接口的实现,
// 这个方法比较狠,个人感觉还是慎用的好
builder.RegisterAssemblyTypes(this.GetType().Assembly)
.AsImplementedInterfaces()
.PropertiesAutowired();
// 默认情况下,构造函数注入和属性注入的结果都是最后注册的那个实现,
// 也就是TestUtil2
private readonly ITestUtil _util;
public HomeController(ITestUtil util, IServiceProvider provider)
{
_util = util;
// 如果知道注册的顺序,可以用这种方式,
// 第一个注册是TestUtil1,所以这里返回TestUtil1
var util1 = provider.GetServices<ITestUtil>().ElementAtOrDefault(0);
util1?.Show("指定注册为ITestUtil的第一个实现");
// 一般情况下用这种方式,指定成具体的类型 TestUtil1
var utilFirst = provider.GetServices<ITestUtil>()
.SingleOrDefault(t => t.GetType() == typeof(TestUtil1));
util1?.Show("指定名称为TestUtil的实现");
}
补充:获取容器 IContainer
下面是官方推荐的方式,定义一个继承自Autofac.Module的类,重写其Load方法,将Startup.cs中ConfigurationContainer方法中的代码全部移至Load的方法内,
请注意该 RmesAutoFacModule
类中定义了一个静态字段 _container
,用于接收注册完成后的Container容器。
在 Load
方法的最后一行,builder
将容器传出,我们使用 _container
接收到,后面就可以直接使用 RmesAutoFacModule.GetContainer()
获取容器了。
public class RmesAutoFacModule : Module
{
private static IContainer _container;
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.AsImplementedInterfaces()
.EnableInterfaceInterceptors();
var controllerBaseType = typeof(ControllerBase);
builder.RegisterAssemblyTypes(typeof(Program).Assembly)
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired() // 允许属性注入
.EnableClassInterceptors(); // 允许在Controller类上使用拦截器
// 手动高亮
builder.RegisterBuildCallback(container => _container = container);
}
public static IContainer GetContainer()
{
return _container;
}
}
在AspNetCore3.0中使用Autofac的更多相关文章
- NET Core 3.0 项目中使用 AutoFac
.net core 3.1 今天已正式发布,3.1跟3.0差别不是很大,主要是对 3.0一小部分修复和完善,最重要的是.NET Core 3.1是长期支持(LTS)版本,建议大家升级. .net co ...
- 在asp.net core2.1中添加中间件以扩展Swashbuckle.AspNetCore3.0支持简单的文档访问权限控制
Swashbuckle.AspNetCore3.0 介绍 一个使用 ASP.NET Core 构建的 API 的 Swagger 工具.直接从您的路由,控制器和模型生成漂亮的 API 文档,包括用于探 ...
- Spring.Net在Mvc4.0中应用的说明
案例Demo:http://yunpan.cn/cJ5aZrm7Uybi3 访问密码 414b Spring.Net在Mvc4.0中应用的说明 1.引用dll 2.修改Global文件 (Spring ...
- Swashbuckle.AspNetCore3.0的二次封装与使用
关于 Swashbuckle.AspNetCore3.0 一个使用 ASP.NET Core 构建的 API 的 Swagger 工具.直接从您的路由,控制器和模型生成漂亮的 API 文档,包括用于探 ...
- 在后台业务管理系统中使用Autofac实现微信接口的处理
在后台业务管理系统中使用Autofac实现微信接口的处理,我们只需要把相关使用到的DLL放到BIN目录里面即可,通过IOC控制反转方式实现对接口的调用.在实现在业务系统里面,我们本身程序可能已经依赖了 ...
- Asp.Net Web Forms/MVC/Console App中使用Autofac
本来简单介绍了Autofac在Asp.Net Web Forms中的应用,后来又添加了mvc.控制台应用程序中使用Autofac,详情请看源码. ASP.NET Web Forms使用Autofac, ...
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十二):在 .NET Core 2.0/3.0 中使用 MessageHandler 中间件
概述 在 <Senparc.Weixin.MP SDK 微信公众平台开发教程(六):了解MessageHandler> 中我们已经了解了 MessageHandler 的运行原理和使用方法 ...
- NetCore 3.0 中使用Swagger生成Api说明文档及升级报错原因
认识Swagger Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参 ...
- 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs
原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...
随机推荐
- WebSocket协议探究(一)
一 复习和目标 1 复习 上一节使用wireshark抓包分析了WebSocket流量 包含连接的建立:HTTP协议升级WebSocket协议 使用建立完成的WebSocket协议发送数据 2 目标 ...
- koa-router学习笔记
koa-router 是koa框架的一个路由处理级别的中间件. 目录结构 ├── app.js ├── middleware │ ├── m1.js │ └── m2.js ├── package-l ...
- centos禁止root用户ssh远程登录
首先,我们要以root身份登录远程主机 vim指令编辑ssh配置文件,如 vim /etc/ssh/sshd_config 查找PermitRootLogin,把yes改为no 修改完配置需要重启ss ...
- JavaScript--常用对象的属性及方法(2)
Array对象(数组) 数组最常用属性:length 获取数组的元素个数 方法: toString() 将数组转换为字符串 var arr = ["武汉市","成都市&q ...
- JavaScript--常用对象的属性及方法(1)
1.Number对象(基本数据类型) Number对象的方法大多是一些强制转换方法,如果转换失败返回NaN,以下举例中用number来代替具体数字: *console.log在控制台输出(键盘F12可 ...
- 组件内或者vuex数据已变化但是页面显示或许不正常
一.问题产生背景: 组件内的数据比较复杂,涉及多层次的数组和对象的情况下,某些值发生变化但是页面值没有变化:更新vuex的数据,同样在涉及多层次的数组和对象的情况下,某些值发生变化但是页面值没有变化: ...
- 简单实现app使用PC图片
提一个很人性化的需求: 在自己的app里使用PC里的图片. 关键点:传输.怎么把图片从PC导入自己的APP. 因为iOS的封闭性,一般用户不能很方便把图片导入手机相册.笔者稍微想了下,实现功能其实也有 ...
- leetcode-111. 二叉树最小深度 · Tree + 递归
题面 找出二叉树的最小深度(从根节点到某个叶子节点路径上的节点个数最小). 算法 算法参照二叉树的最大深度,这里需要注意的是当某节点的左右孩子都存在时,就返回左右子树的最小深度:如果不都存在,就需要返 ...
- Linux常用命令及文件管理
Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示. 目录解释: .代表此层目录: .. 代表父目录:-代表前一个目录:~代表是家目录. (1)ls命令(显示) -a:列出所有文 ...
- docker从入门到精通再到放弃
docker说明 docker三大功能:构建(build).运输(ship).运行(run),只需要记下这三大功能就可以了 1.docker入门 docker安装及配置 a.docker源配置 cur ...