- A+
本节演示在 .net Core ApI项目中引入 Autofac 容器
项目前提条件:
.net Core ApI项目
服务层--Service层
仓储层--Repository层
。。
第一步:安装 NuGet 相关包,安装如下两个Autofac 包即可,目前版本 Autofac 6.0
第二步: 注册
Program.cs 文件中需要加入一句话:.UseServiceProviderFactory(new AutofacServiceProviderFactory())
/// <summary> /// 默认初始化系统内置的配置 /// </summary> /// <param name="args"></param> /// <returns></returns> public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //autofac 依赖注入 .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
Startup.cs 文件中加入如下方法,固定写法,方法内容暂时先空着,下边继续。。。
/// <summary> /// Autofac引用 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) { //注册逻辑 }
到这里,配置操作基本上结束了,接下来根据业务具体操作!
业务场景:假如有一个通知系统,具体业务就是公司老板通过电话系统通知手下都需要干什么事情!
在服务层 MyShop.Services 创建一个通知接口,并且实现该接口:
public interface IMessageNotice { string Send(string arg); //发送通知 } /// <summary> /// 实现类1 电话通知 /// </summary> public class MobileNotice : IMessageNotice { public string Send(string arg) { return $"电话通知系统,通知内容:{arg}"; } }
在 Startup.cs 文件中注册上边接口,builder.RegisterType<MobileNotice>().As<IMessageNotice>()
/// <summary> /// Autofac引用 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) { //单个注册 builder.RegisterType<MobileNotice>().As<IMessageNotice>(); }
在控制器Controller中注入 IMessageNotice接口
public class NoticeController : ControllerBase { private readonly IMessageNotice messageNotice; public NoticeController(IMessageNotice _messageNotice) { messageNotice = _messageNotice; } /// <summary> /// 电话通知 /// </summary> /// <returns></returns> [HttpGet] public async Task<IActionResult> MobileNotice() { string content = "下午不用上班"; var result = await messageNotice.Send(content); return Ok(result); } }
然后运行测试:
假如:现在业务需求变了,老板说了,现在互联网时代,电话沟通已经不是唯一的工具了,还要系统可以通过微信沟通,同时以前的电话通知也要支持!
很简单,再写个微信通知类,实现通知接口: IMessageNotice
1 /// <summary> 2 /// 微信通知 3 /// </summary> 4 public class WebChatNotice : IMessageNotice 5 { 6 //普通发送 7 public string Send(string arg) 8 { 9 return $"微信通知系统,通知内容:{arg}"; 10 } 11 12 //异步发送 13 public Task<string> SendAsync(string arg) 14 { 15 return Task.Run(() => { return $"微信通知系统,通知内容:{arg}"; }); 16 } 17 18 }
同时在 Startup 中注册微信接口
/// <summary> /// Autofac引用 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) { //注册电话接口 builder.RegisterType<MobileNotice>().As<IMessageNotice>(); //注册微信接口 builder.RegisterType<WebChatNotice>().As<IMessageNotice>(); }
再次运行,发现电话通知变成微信通知了!但是电话通知却没有了,这是因为上边 微信接口注册时,自动把电话接口注册覆盖了!
老板的要求是同时支持电话通知和微信通知,现在明显不符合需求,那就继续改!
修改注册类,使用 Named<T>方法区分不同的实现类
/// <summary> /// Autofac引用 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) { //注册电话接口 builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile"); //注册微信接口 builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat"); }
然后新建个Manager文件夹,添加一个通知管理类:NoticeManager,使用Autofac内置接口 ILifetimeScope 来实现接口调用
/// <summary> /// 通知管理类 /// </summary> public class NoticeManager { //ILifetimeScope 是Autofac内置类 private readonly ILifetimeScope messageNotice; public NoticeManager(ILifetimeScope _messageNotice) { messageNotice = _messageNotice ?? throw new ArgumentNullException(nameof(_messageNotice)); } //发送通知 public List<string> SendNotice(string arg) { var list = new List<string>(); //使用 ResolveNamed<T>方法区分 var mobile = messageNotice.ResolveNamed<IMessageNotice>("mobile"); //电话通知 var webchat = messageNotice.ResolveNamed<IMessageNotice>("webchat"); //微信通知 list.Add(mobile.Send(arg)); //调用发送电话通知 list.Add(webchat.Send(arg)); //调用发送微信通知 return list; } }
同时在 Startup.cs 中注册 NoticeManager 类,自己注册自己,相当于new了一个实例
然后在控制器Controller里,通过构造方法注入通知管理类 NoticeManager
private readonly NoticeManager messageNotice; public NoticeController(NoticeManager _messageNotice) { messageNotice = _messageNotice; } /// <summary> /// 通知 /// </summary> /// <returns></returns> [HttpGet] public async Task<IActionResult> MobileNotice() { string content = "下午不用来上班"; var getlist = await Task.Run(() => { return messageNotice.SendNotice(content); }); return Ok(getlist); }
现在再次运行,已经按照老板的需求同时支持电话和微信通知了!
第三步:批量注册
使用 RegisterAssemblyTypes 方法可以按照程序集实现批量注册,好处就不多说了!
批量注册和单个类型注册不冲突,可以同时存在!
/// <summary> /// Autofac引用 /// </summary> /// <param name="builder"></param> public void ConfigureContainer(ContainerBuilder builder) { //注册电话接口 builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile"); //注册微信接口 builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat"); //注册管理类 自己注册自己 //builder.RegisterType<NoticeManager>(); //批量注册程序集 没有接口,并且以Manager结尾的类,可以代替上边的 NoticeManager类注册 var myshopapibll = Assembly.Load("MyShopApi"); builder.RegisterAssemblyTypes(myshopapibll) .Where(t=>t.Name.EndsWith("Manager")); //批量注册程序集 有接口 var basedir = AppContext.BaseDirectory; var bllservice = Path.Combine(basedir, "MyShop.Services.dll"); if (!File.Exists(bllservice)) { var msg = "MyShop.Services.dll不存在"; throw new Exception(msg); } var assemblysServices = Assembly.LoadFrom(bllservice); //Assembly.Load("MyShop.Services"); builder.RegisterAssemblyTypes(assemblysServices) //多个程序集用逗号","分割 .AsImplementedInterfaces() //批量关联,让所有注册类型自动与其继承的接口进行关联 .InstancePerDependency(); //瞬时模式 }
批量注册类型,当一个接口存在多个实现类时,如果不用 Named<T> 方法区分,也可以使用 IEnumerable<T> 方式注入构造函数获取实例,两者效果相同,如下标红部分:
public class NoticeManager { private readonly ILifetimeScope lifetimeScope; //ILifetimeScope 是Autofac内置类 private readonly IEnumerable<IMessageNotice> messageNotices; //使用IEnumerable<IMessageNotice>格式注入 public NoticeManager(ILifetimeScope _lifetimeScope, IEnumerable<IMessageNotice> _messageNotices) { lifetimeScope = _lifetimeScope ?? throw new ArgumentNullException(nameof(_lifetimeScope)); messageNotices = _messageNotices ?? throw new ArgumentNullException(nameof(_messageNotices)); } //发送通知 public List<string> SendNotice(string arg) { var list = new List<string>(); //方式1:使用 ResolveNamed<T>方法区分 //var mobile = lifetimeScope.ResolveNamed<IMessageNotice>("mobile"); //电话通知 //var webchat = lifetimeScope.ResolveNamed<IMessageNotice>("webchat"); //微信通知 //方式2 使用IEnumerable<IMessageNotice> 获取实例,效果和 Named<T> 注册相同 var mobile = messageNotices.Where(t=>t.GetType()==typeof(MobileNotice)).FirstOrDefault(); //电话通知 var webchat = messageNotices.Where(t => t.GetType() == typeof(WebChatNotice)).FirstOrDefault(); //微信通知 list.Add(mobile.Send(arg)); //发送电话通知 list.Add(webchat.Send(arg)); //发送微信通知 return list; } }
测试结果跟上边一样
第四步:扩展
为了使代码显的更整洁,可以对 Autofac注册内容进行封装!
新建一个扩展文件夹:Extensions,然后在里边新建一个扩展类:AutofacExtension 并继承 Autofac.Module,然后把 Startup.cs 中Autofac的注册内容剪切过来!
1 public class AutofacExtension : Autofac.Module 2 { 3 //重写Load函数 4 protected override void Load(ContainerBuilder builder) 5 { 6 //注册电话接口 7 builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile"); 8 9 //注册微信接口 10 builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat"); 11 12 //注册管理类 自己注册自己 13 //builder.RegisterType<NoticeManager>(); 14 15 //批量注册程序集 没有接口,并且以Manager结尾的类,可以代替上边的 NoticeManager类注册 16 var myshopapibll = Assembly.Load("MyShopApi"); 17 builder.RegisterAssemblyTypes(myshopapibll) 18 .Where(t => t.Name.EndsWith("Manager")); 19 20 21 //批量注册程序集 有接口 22 var basedir = AppContext.BaseDirectory; 23 var bllservice = Path.Combine(basedir, "MyShop.Services.dll"); 24 if (!File.Exists(bllservice)) 25 { 26 var msg = "MyShop.Services.dll不存在"; 27 throw new Exception(msg); 28 } 29 var assemblysServices = Assembly.LoadFrom(bllservice); //Assembly.Load("MyShop.Services"); 30 builder.RegisterAssemblyTypes(assemblysServices) //多个程序集用逗号","分割 31 .AsImplementedInterfaces() //批量关联,让所有注册类型自动与其继承的接口进行关联 32 .InstancePerDependency(); //瞬时模式 33 } 34 }
同时修改 Startup 文件中的内容如下:
1 /// <summary> 2 /// Autofac引用 3 /// </summary> 4 /// <param name="builder"></param> 5 public void ConfigureContainer(ContainerBuilder builder) 6 { 7 builder.RegisterModule(new AutofacExtension()); 8 }
这里只是记录常用的一部分,还有很多扩展没有记录,比如实现AOP等,以后再慢慢补充吧! 到此结束!