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);
}
}
二、修改StartupConfigureContainer方法

注意:

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;
}
}

最新文章

  1. [Linux]系统调用理解(1)
  2. VR技术的探索阶段
  3. ng指令之 ng-class 篇
  4. 基于Bootstrap的jQuery开关按钮插件
  5. loadruner报错:Step download timeout(120 seconds)的一个解决方法
  6. zend studio 12.0 怎么汉化?
  7. [kuangbin带你飞]专题一 简单搜索
  8. 浏览器中JavaScript执行原理
  9. “#ifdef __cplusplus extern &quot;C&quot; { #endif”的定义
  10. java web 之 WebRoot和WebContent目录
  11. 语句、变量等js最基本知识
  12. word中正文分栏重新换页问题
  13. Android View框架总结(九)KeyEvent事件分发机制
  14. Mysql-自带的一些功能,基本用法(视图,触发器,事务,存储过程,函数,流程控制)
  15. android 百度地图 定位获取位置失败 62错误
  16. mybatis事务管理机制详解
  17. cut语法
  18. Keil MDK忽略警告:文件末尾空白行警告
  19. google最新的书签导入导出
  20. ActiveMQ的消息存储方式

热门文章

  1. .netcore 和.netFrameWork
  2. docker系列三之docker的安装
  3. vue在axios中 this 指向问题
  4. Linux的关机和重启命令
  5. MySQL数据库的启动与停止
  6. 从c到c++&lt;一&gt;
  7. java学习笔记13-重写与重载
  8. Java&amp;Selenium数据驱动【DataProvider+TestNG+Csv】
  9. Java基础 使用转换流进行文件的复制 / RandomAccessFile 类进行文件的复制
  10. Spring-整合MyBatis-声明式事务