.Net Core5.0中Autofac依賴注入整合多層,項目中可直接用
一、配置Autofac替換內置DI
1.安裝Nuget包:Autofac,Autofac.Extensions.DependencyInjection

2.Program.cs中CreateHostBuilder方法后加上.UseServiceProviderFactory(new AutofacServiceProviderFactory()) ; 告訴程序要使用Autofac。

3.Startup.cs中增加方法ConfigureContainer(ContainerBuilder containerBuilder),實例注入的地方,配置完成。
/// <summary>
/// Autofac注冊服務的地方,Autofac會自動調用
/// </summary>
/// <param name="containerBuilder"></param>
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
}
二、構造函數注入
新建IUserService,類UserService,控制器UserController
public interface IUserService
{
public string GetUserName();
}
public class UserService
{
public string GetUserName()
{
return "張三";
}
}
public class UserController : Controller
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
public IActionResult Index()
{
string name = _userService.GetUserName();
return Content(name);
}
}
在上面的ConfigureContainer方法把UserService注入進來,默認是瞬時注入
瞬時注入:containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerDependency();;
單例注入:containerBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance();
生命周期注入: containerBuilder.RegisterType<UserService>().As<IUserService>().InstancePerLifetimeScope();
/// <summary>
/// Autofac注冊服務的地方,Autofac會自動調用
/// </summary>
/// <param name="containerBuilder"></param>
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
//注冊服務
containerBuilder.RegisterType<UserService>().As<IUserService>();
}
訪問/User/Index,_userService成功注入,正確獲取結果。

三、屬性注入
1.把UserController改成屬性注入形式,屬性注入有一個問題,就是那些屬性需要注入?全部注入沒必要,父類也有很多屬性,要按需注入,給屬性增加一個自定義特性標識說明需要注入。
public class UserController : Controller
{
[AutowiredProperty]
private IUserService userService { get; set; }
public IActionResult Index()
{
string name = userService.GetUserName();
return Content(name);
}
}
2.新增自定義特性類AutowiredPropertyAttribute.cs
[AttributeUsage(AttributeTargets.Property)]//為了支持屬性注入,只能打到屬性上
public class AutowiredPropertyAttribute : Attribute
{
}
3.增加識別特性類AutowiredPropertySelector.cs
/// <summary>
/// IPropertySelector:查看屬性上是否標記某一個特性
/// </summary>
public class AutowiredPropertySelector : IPropertySelector
{
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
//判斷屬性的特性是否包含自定義的屬性,標記有返回true
return propertyInfo.CustomAttributes.Any(s => s.AttributeType == typeof(AutowiredPropertyAttribute));
}
}
4.因為Controller 默認是由 Mvc 模塊管理的,需要把控制器放到IOC容器中,在Startup.cs的ConfigureServices中增加
//讓控制器實例由容器創建 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

5.把容器注冊到IOC容器,在Startup.cs的ConfigureContainer()增加
//獲取所有控制器類型並使用屬性注入
Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

6.驗證結果,新增一個接口IOrderService.cs和一個實現類OrderService.cs做對比
public interface IOrderService
{
public string CreateOrder();
}
public class OrderService : IOrderService
{
public string CreateOrder()
{
return "下單成功";
}
}
把UserController改成
public class UserController : Controller
{
[AutowiredProperty]
private IUserService userService { get; set; }
private IOrderService orderService { get; set; }//不加屬性注入標識
public IActionResult Index()
{
string name = userService.GetUserName();
return Content(name);
}
}
注入方法ConfigureContainer()增加
containerBuilder.RegisterType<OrderService>().As<IOrderService>();
運行程序,能看到增加了注入標識的userService注入成功,沒加標識的orderService沒有注入。

四、批量注入
實際項目中那么多需要注入的類,一個個寫注冊就不太現實了,需要一個可以批量注入的方法。
1.新建三個空接口IScopeDenpendency.cs,ISingletonDenpendency.cs,ITransitDenpendency.cs
/// <summary>
/// 瞬時注入
/// </summary>
public interface ITransitDenpendency
{
}
/// <summary>
/// 單例注入標識
/// </summary>
public interface ISingletonDenpendency
{
}
/// <summary>
/// 生命周期注入標識
/// </summary>
public interface IScopeDenpendency
{
}
2.把上面要注入的類實現上面的接口

3.新增一個IocManger類
/// <summary>
/// 批量注入擴展
/// </summary>
/// <param name="builder"></param>
/// <param name="assembly"></param>
public static void BatchAutowired(this ContainerBuilder builder, Assembly assembly)
{
var transientType = typeof(ITransitDenpendency); //瞬時注入
var singletonType = typeof(ISingletonDenpendency); //單例注入
var scopeType = typeof(IScopeDenpendency); //單例注入
//瞬時注入
builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(transientType))
.AsSelf()
.AsImplementedInterfaces()
.InstancePerDependency()
.PropertiesAutowired(new AutowiredPropertySelector());
//單例注入
builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(singletonType))
.AsSelf()
.AsImplementedInterfaces()
.SingleInstance()
.PropertiesAutowired(new AutowiredPropertySelector());
//生命周期注入
builder.RegisterAssemblyTypes(assembly).Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Contains(scopeType))
.AsSelf()
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.PropertiesAutowired(new AutowiredPropertySelector());
}
4.把注入類ConfigureContainer改成
/// <summary>
/// Autofac注冊服務的地方,Autofac會自動調用
/// </summary>
/// <param name="containerBuilder"></param>
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
//獲取所有控制器類型並使用屬性注入
Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
//批量自動注入,把需要注入層的程序集傳參數
containerBuilder.BatchAutowired(typeof(UserService).Assembly);
containerBuilder.BatchAutowired(typeof(UserRepository).Assembly);
}
5.防止startup.cs代碼過多,建一個Module把注入代碼搬走,新建AutofacRegisterModule.cs類把ConfigureContainer的代碼移過去
public class AutofacRegisterModule:Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
//獲取所有控制器類型並使用屬性注入
Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());
//批量自動注入,把需要注入層的程序集傳參數
builder.BatchAutowired(typeof(UserService).Assembly);
builder.BatchAutowired(typeof(UserRepository).Assembly);
}
}
ConfigureContainer的代碼變成
/// <summary>
/// Autofac注冊服務的地方,Autofac會自動調用
/// </summary>
/// <param name="containerBuilder"></param>
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterModule<AutofacRegisterModule>();
}
五、手動獲取實例
手動獲取實例的場景有靜態幫助類中獲取實例,例如redisHelper中獲取注入的配置文件中的連接字符串
1.在上面的IocManager類中增加
private static object obj = new object();
private static ILifetimeScope _container { get; set; }
public static void InitContainer(ILifetimeScope container)
{
//防止過程中方法被調用_container發生改變
if (_container == null)
{
lock (obj)
{
if (_container == null)
{
_container = container;
}
}
}
}
/// <summary>
/// 手動獲取實例
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
2.在Startup.cs的Configure()中增加
//獲取Autofac容器上下文信息
IocManager.InitContainer(app.ApplicationServices.GetAutofacRoot());
3.驗證,新建一個DataHelper.cs類
public class DataHelper
{
//手動注入UserService
private static IUserService userService = IocManager.Resolve<IUserService>();
public static string GetData()
{
return userService.GetUserName();
}
}
修改UserController用DataHelper的方法成功獲取數據

六、其它用法
1.不用接口,直接注入實例
public class UserService :ITransitDenpendency
{
public string GetUserName()
{
return "張三";
}
}

2.一接口多實現
public class UserService :IUserService
{
public string GetUserName()
{
return "張三";
}
}
public class User2Service : IUserService
{
public string GetUserName()
{
return "張三2號";
}
}

最后:源碼地址:https://github.com/weixiaolong325/.NetCore5.0AutofacDemo
演示項目結構:

原文鏈接:https://www.cnblogs.com/wei325/archive/2021/08/11/15121451.html

