Autofac 是一個輕量級的依賴注入(DI)架構,它可以幫助 .NET 開發人員更好地管理對象的生命周期和依賴關系。Autofac 可以大大簡化應用程式中對象之間的耦合,使代碼更加可維護和可測試。
Autofac 的主要特點:
輕量級:Autofac 是一個非常輕量級的架構,其核心庫隻有幾個 DLL 檔案。這意味着它可以很容易地與其他架構內建,并且對應用程式的性能沒有任何影響。
靈活性:Autofac 提供了多種不同的注冊方式,如 XML 配置檔案、代碼配置和屬性注解等。開發人員可以根據自己的需求選擇最适合的注冊方式。
高性能:由于 Autofac 是一個輕量級架構,它的性能非常高。在執行個體化對象時,Autofac 可以比其他 DI 架構更快地找到并建立所需的依賴項。
生命周期管理:Autofac 提供了多種不同的生命周期管理選項,如瞬态(Transient)、作用域(Scoped)和單例(Singleton)等。這使得開發人員可以更好地控制對象的生命周期,有效地降低記憶體使用和提高性能。
AOP 支援:Autofac 可以輕松地與 AOP 架構內建,如 Castle DynamicProxy 等。這使得開發人員可以很容易地實作諸如事務管理、緩存和驗證等方面的橫切關注點。
Autofac 其核心思想是将對象之間的依賴關系從應用程式中分離出來。相對于傳統的執行個體化對象方式,DI 可以有效地降低代碼的耦合度,提高可維護性和可測試性。
Autofac 的架構主要分為兩個部分:注冊器(ContainerBuilder)和容器(IContainer)。注冊器用于注冊應用程式中所有需要注入的服務群組件,而容器則用于建立和管理這些元件執行個體。
注入方式
先準備點代碼
接口層代碼:粘貼太麻煩了,直接貼圖,代碼也很簡單
貓的接口
狗的接口
豬的接口
技能接口
人的接口
實作層代碼:粘貼太麻煩了,直接貼圖,代碼也很簡單
貓的實作
狗的實作
豬的實作
人的實作
上面代碼準備好了。我們搞注入
構造函數注入 (預設的注入方式)
{
//構造函數注入
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<PersonService>().As<IPersonService>();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
}
上面代碼通過RegisterType引入IDogService,後引入IPersonService,會執行PersionService中有一個IDogService作為參數的構造函數
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<PigService>().As<IPigService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<PersonService>().As<IPersonService>();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
}
上面代碼通過RegisterType引入了IDogService、ICatService、IPigService,是以會走具有三個參數的構造函數
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
//通過UsingConstructor方法指定要執行的構造函數
builder.RegisterType<PersonService>().As<IPersonService>().UsingConstructor(typeof(IDogService), typeof(ICatService));
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.Say();
p.PlayerWithDog();
p.PlayerWithCat();
}
上面代碼通過RegisterType引入了IDogService、ICatService、再通過UsingConstructor方法指定要執行的構造函數,是以會走具有二個參數的構造函數
屬性注入
準備代碼,簡單代碼直接貼圖
動物接口
動物實作
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
//PropertiesAutowired 使AnimalService執行個體的屬性可以被注入
builder.RegisterType<AnimalService>().As<IAnimalService>().PropertiesAutowired();
IContainer container = builder.Build();
var p = container.Resolve<IAnimalService>();
p.Say();
}
上面代碼 調用PropertiesAutowired 方法,使AnimalService執行個體的屬性可以被注入
屬性注入(屬性注入選擇器)
自定義一個空的特性
自定義屬性選擇器
動物實作2
{
//屬性注入 屬性注入選擇器
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
//PropertiesAutowired 使AnimalService2執行個體的屬性可以被注入
builder.RegisterType<AnimalService2>().As<IAnimalService>().PropertiesAutowired(new IoctAttributeSelector());
IContainer container = builder.Build();
var p = container.Resolve<IAnimalService>();
p.Say();
}
上面代碼 調用PropertiesAutowired(new IoctAttributeSelector()) 方法,使AnimalService2執行個體的屬性可以被選擇注入
方法注入
所謂方法注入是指:在接口對象構造後,自動調用對象的某個方法
{
//方法注入 所謂方法注入是指:在接口對象構造後,自動調用對象的某個方法
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().As<IDogService>();
builder.RegisterType<CatService>().As<ICatService>();
builder.RegisterType<PigService>().As<IPigService>();
builder.RegisterType<AnimalService>().As<IAnimalService>().OnActivated(Activator =>
{
var dogService = Activator.Context.Resolve<IDogService>();
var catService = Activator.Context.Resolve<ICatService>();
var pigService = Activator.Context.Resolve<IPigService>();
Activator.Instance.Play(catService, dogService, pigService);
});
IContainer container = builder.Build();
//建構IAnimalService對象,觸發上述Play方法執行
var p = container.Resolve<IAnimalService>();
}
上面代碼,構造了AnimalService的執行個體後自動調用Play方法
單抽象多繼承 通過加入key來識别
{
//單抽象多繼承 通過加入key來識别即可,如下
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<DogService>().Keyed<ISkillService>("dog");
builder.RegisterType<CatService>().Keyed<ISkillService>("cat");
builder.RegisterType<PigService>().Keyed<ISkillService>("pig");
IContainer container = builder.Build();
//這裡是狗
var dog = container.ResolveKeyed<ISkillService>("dog");
dog.ReleaseSkills();
//這裡是貓
var cat = container.ResolveKeyed<ISkillService>("cat");
cat.ReleaseSkills();
//這裡是豬
var pig = container.ResolveKeyed<ISkillService>("pig");
pig.ReleaseSkills();
}
上面代碼,貓、狗、豬分别用key辨別來分别
泛型注入
先準備點代碼,貼圖
一個參數的泛型接口
兩個參數的泛型接口
一個參數的實作
兩個參數的實作
{
//泛型注入
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(GenericAService<>)).As(typeof(IGenericAService<>));
builder.RegisterGeneric(typeof(GenericBService<,>)).As(typeof(IGenericBService<,>));
IContainer container = builder.Build();
var p = container.Resolve<IGenericAService<Dog>>();
var name1 = p.GetFullName();
var p2 = container.Resolve<IGenericBService<Dog, Cat>>();
var name2 = p2.GetFullName();
}
通過程式集加載1
{
//通過程式集加載
ContainerBuilder builder = new ContainerBuilder();
Assembly assemblyInterface = Assembly.LoadFrom("ITestLibraryService.dll");
Assembly assemblyService = Assembly.LoadFrom("TestLibraryService.dll");
builder.RegisterAssemblyTypes(assemblyInterface, assemblyService).AsImplementedInterfaces();
IContainer container = builder.Build();
//PersonService 會執行參數多的構造函數
var p = container.Resolve<IPersonService>();
p.PlayerWithDog();
p.PlayerWithCat();
p.PlayerWithPig();
}
這裡需要說明的是,如果構造函數中有相同參數個數的構造函數,AutoFac會報錯,他就不知道該執行哪個構造函數了。
通過程式集加載2
{
//通過程式集加載
ContainerBuilder builder = new ContainerBuilder();
Assembly iService = Assembly.Load("ITestLibraryService");
Assembly service = Assembly.Load("TestLibraryService");
builder.RegisterAssemblyTypes(iService, service).Where(p => p.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
IContainer container = builder.Build();
var p = container.Resolve<IPersonService>();
p.PlayerWithDog();
p.PlayerWithCat();
p.PlayerWithPig();
}
上面代碼,規定了名稱必須是Service結尾的
接下來我們聊一聊WebApi中如何使用Autofac 架構
Nuget 先引用幾個包
引用
<ItemGroup>
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Autofac.Extras.DynamicProxy" Version="7.1.0" />
<PackageReference Include="Castle.Core" Version="5.1.1" />
</ItemGroup>
Program 添加如下代碼
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>((builder) =>
{
var controllersTypesInAssembly = typeof(Program).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); //控制器支援屬性注入
builder.RegisterGeneric(typeof(GenericAService<>)).As(typeof(IGenericAService<>));
builder.RegisterGeneric(typeof(GenericBService<,>)).As(typeof(IGenericBService<,>));
Assembly iService = Assembly.Load("ITestLibraryService");
Assembly service = Assembly.Load("TestLibraryService");
builder.RegisterAssemblyTypes(iService, service).Where(p => p.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();
});
控制器就可以使用了
控制器代碼
生命周期的管理
InstancePerDependency 瞬時
builder.RegisterType<TestAService>().As<ITestAService>().InstancePerDependency();
InstancePerLifetimeScope() 範圍
builder.RegisterType<TestBService>().As<ITestBService>().InstancePerLifetimeScope();
InstancePerMatchingLifetimeScope("name名稱") *比對 name* 聲明周期範圍執行個體
builder.RegisterType<TestDService>().As<ITestDService>().InstancePerMatchingLifetimeScope("myscope");
SingleInstance 單例
builder.RegisterType<TestCService>().As<ITestCService>().SingleInstance();
AOP Castle DynamicProxy 動态代理 面向切片程式設計
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace CastleDynamicProxyDemo
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// ...
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>((builder) =>
{
var controllersTypesInAssembly = typeof(Program).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); //控制器支援屬性注入
builder.RegisterType<SimpleService>().As<ISimpleService>()
.EnableInterfaceInterceptors().InterceptedBy(typeof(LogInvocationInterceptor));
builder.RegisterType<LogInvocationInterceptor>().SingleInstance();
});
var app = builder.Build();
//.....
app.Run();
}
}
}
攔截器
using Castle.DynamicProxy;
namespace CastleDynamicProxyDemo
{
public class LogInvocationInterceptor : IInterceptor
{
private readonly ILogger<LogInvocationInterceptor> _logger;
public LogInvocationInterceptor(ILogger<LogInvocationInterceptor> logger)
{
_logger = logger;
}
public void Intercept(IInvocation invocation)
{
PrevProceed(invocation);
Proceed(invocation);
AfterProceed(invocation);
}
/// <summary>
/// 繼續執行
/// </summary>
/// <param name="invocation"></param>
protected virtual void Proceed(IInvocation invocation)
{
//繼續,這句是真的調用服務的方法
invocation.Proceed();
}
/// <summary>
/// 執行前
/// </summary>
/// <param name="invocation"></param>
protected virtual void PrevProceed(IInvocation invocation)
{
_logger.LogInformation(invocation.Method.Name);
_logger.LogInformation(#34;{invocation.Arguments}");
}
/// <summary>
/// 執行後
/// </summary>
/// <param name="invocation"></param>
protected virtual void AfterProceed(IInvocation invocation)
{
_logger.LogInformation(invocation.ReturnValue.ToString());
}
}
}
一個簡單的服務
服務的實作
控制器調用
調試下執行過程
執行前
執行
執行後