在使用 Autofac 框架進行開發后,撰寫集成測驗時,需要用 Mock 的用于測驗的模擬的型別去代替容器里面已注入的實際型別,也就需要在 Autofac 完全收集完成之后,再次注入模擬的物件進行覆寫原有業務代碼注冊的正式物件,但 Autofac 默認沒有提供此機制,我閱讀了 Autofac 的源代碼之后,創建了一些輔助代碼,實作了此功能,本文將告訴大家如何在集成測驗里面,在使用了 Autofac 的專案里面,在所有收集完成之后,注入用于測驗的 Mock 型別,和 Autofac 接入的原理
背景
為什么選擇使用 Autofac 框架?原因是在此前的 WPF 專案里面,有使用過的是 MEF 和 Autofac 兩個框架,而 MEF 的性能比較糟心,解決 MEF 性能問題的是 VS-MEF 框架,在后續開發的一個 ASP.NET Core 專案里面,也就自然選用了 Autofac 框架
對比原生的 ASP.NET Core 自帶的 DI 框架,使用 Autofac 的優勢在于支持模塊化的初始化,支持屬性注入
默認的 Autofac 可以通過 Autofac.Extensions.DependencyInjection 將 Autofac 和 dotnet 通用依賴注入框架合入在一起,但在 Autofac 里面的定制要求是在 Startup 的 ConfigureContainer 函式里面進行依賴注入,也就是在默認的 ASP.NET Core 里面沒有提供更靠后的依賴注入方法,可以在完成收集之后,再次注入測驗所需要的型別,覆寫業務代碼里面的實際物件
需求
假定在一個應用,如 ASP.NET Core 應用里面,進行集成測驗,想要在集成測驗里面,使用專案里面的依賴注入關系,只是將部分型別替換為測驗專案里面的模擬的型別
而在應用里面,實際的業務型別是在 Autofac 的 Module 進行注入的,在應用里面的大概邏輯如下,在 Program 的 CreateHostBuilder 函式里面通過 UseServiceProviderFactory 方法使用 Autofac 替換 原生 的框架
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
// 使用 auto fac 代替默認的 IOC 容器
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
在 Startup 里面添加 ConfigureContainer 方法,代碼如下
public void ConfigureContainer(ContainerBuilder builder)
{
}
在 ConfigureContainer 里面注入具體的需要初始化的業務模塊,例如 FooModule 模塊,在具體模塊里面注入實際業務的型別,如 Foo 型別,代碼如下
public class Startup
{
// 忽略代碼
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new FooModule());
}
}
class FooModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
Console.WriteLine($"06 FooModule");
builder.RegisterType<Foo>().As<IFoo>();
}
}
public class Foo : IFoo
{
}
public interface IFoo
{
}
現在的需求是在集成測驗里面,將 IFoo 的實際型別從 Foo 替換為 TestFoo 型別
在集成測驗專案里面,可以使用如下代碼獲取實際的專案的依賴注入收集
var hostBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseTestServer(); //關鍵是多了這一行建立TestServer
})
// 使用 auto fac 代替默認的 IOC 容器
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
var host = hostBuilder.Build();
var foo = host.Services.GetService<IFoo>();
以上的 foo 就是從收集的容器里面獲取的 IFoo 物件,以上代碼獲取到的是業務代碼的 Foo 型別物件,假定需要讓容器里面的 IFoo 的實際型別作為測驗的 TestFoo 型別,就需要在實際專案的依賴注入收集完成之前,進行測驗的注入
但實際上沒有在 Autofac 里面找到任何的輔助方法可以用來實作此功能,如果是默認的應用框架,可以在 ConfigureWebHostDefaults 函式之后,通過 ConfigureServices 函式覆寫在 Startup 的 ConfigureServices 函式注入的型別
實作方法
實作的方法是很簡單的,關于此實作為什么能解決問題還請參閱下文的原理部分
集成測驗專案不需要改動原有的業務專案即可完成測驗,實作方法是在集成測驗專案里面添加 FakeAutofacServiceProviderFactory 用來替換 Autofac 的 AutofacServiceProviderFactory 型別,代碼如下
class FakeAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
public FakeAutofacServiceProviderFactory(
ContainerBuildOptions containerBuildOptions = ContainerBuildOptions.None,
Action<ContainerBuilder>? configurationActionOnBefore = null,
Action<ContainerBuilder>? configurationActionOnAfter = null)
{
_configurationActionOnAfter = configurationActionOnAfter;
AutofacServiceProviderFactory =
new AutofacServiceProviderFactory(containerBuildOptions, configurationActionOnBefore);
}
private AutofacServiceProviderFactory AutofacServiceProviderFactory { get; }
private readonly Action<ContainerBuilder>? _configurationActionOnAfter;
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
return AutofacServiceProviderFactory.CreateBuilder(services);
}
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
_configurationActionOnAfter?.Invoke(containerBuilder);
return AutofacServiceProviderFactory.CreateServiceProvider(containerBuilder);
}
}
可以看到本質的 FakeAutofacServiceProviderFactory 實作就是通過 AutofacServiceProviderFactory 的屬性實作,只是在 CreateServiceProvider 方法里面加入了委托,可以方便在單元測驗里面進行注入自己的方法
在集成測驗專案里面的使用方法如下
var hostBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseTestServer(); //關鍵是多了這一行建立TestServer
})
// 使用 auto fac 代替默認的 IOC 容器
.UseServiceProviderFactory(new FakeAutofacServiceProviderFactory(configurationActionOnAfter:
builder =>
{
builder.RegisterModule<TestModule>();
}));
傳入的委托需要注入測驗的初始化模塊,也就是 TestModule 需要加入注入,通過上面代碼,可以讓 TestModule 在依賴注入的最后進行初始化,在 TestModule 里面加入實際的測驗型別注入的代碼
class TestModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<TestFoo>().As<IFoo>();
}
}
class TestFoo : IFoo
{
}
通過上面方法就可以讓集成測驗專案從容器里面獲取 IFoo 的物件,拿到的是 TestFoo 型別,集成測驗專案的代碼如下
[TestClass]
public class FooTest
{
[ContractTestCase]
public void Test()
{
"依賴注入的時機,可以在完成收集之后,覆寫原有的型別".Test(() =>
{
var hostBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseTestServer(); //關鍵是多了這一行建立TestServer
})
// 使用 auto fac 代替默認的 IOC 容器
.UseServiceProviderFactory(new FakeAutofacServiceProviderFactory(configurationActionOnAfter:
builder =>
{
builder.RegisterModule<TestModule>();
}));
var host = hostBuilder.Build();
var foo = host.Services.GetService<IFoo>();
Assert.IsInstanceOfType(foo, typeof(TestFoo));
});
}
}
class TestModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<TestFoo>().As<IFoo>();
}
}
class TestFoo : IFoo
{
}
class FakeAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
public FakeAutofacServiceProviderFactory(
ContainerBuildOptions containerBuildOptions = ContainerBuildOptions.None,
Action<ContainerBuilder>? configurationActionOnBefore = null,
Action<ContainerBuilder>? configurationActionOnAfter = null)
{
_configurationActionOnAfter = configurationActionOnAfter;
AutofacServiceProviderFactory =
new AutofacServiceProviderFactory(containerBuildOptions, configurationActionOnBefore);
}
private AutofacServiceProviderFactory AutofacServiceProviderFactory { get; }
private readonly Action<ContainerBuilder>? _configurationActionOnAfter;
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
return AutofacServiceProviderFactory.CreateBuilder(services);
}
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
_configurationActionOnAfter?.Invoke(containerBuilder);
return AutofacServiceProviderFactory.CreateServiceProvider(containerBuilder);
}
}
以上集成測驗使用了 CUnit 中文單元測驗框架輔助,在上面代碼里面,可以看到集成測驗里面的容器拿到的 IFoo 物件就是 TestFoo 型別,通過這個方法就可以在業務代碼執行程序,注入測驗需要的型別
為什么通過以上的代碼即可實作此功能,為什么需要自己實作一個 FakeAutofacServiceProviderFactory 型別,為什么不能在 AutofacServiceProviderFactory.CreateServiceProvider 方法之前注入型別,而是需要再定義一個 TestModule 模塊,在測驗初始化模塊進行初始化,更多細節請看下文
原理
回答以上問題,需要了解各個注入方法呼叫的順序,我在代碼里面通過控制臺輸出各個方法的順序,標記了順序的代碼放在本文最后
以下是按照呼叫順序的方法代碼
Startup 的 ConfigureServices 方法
public class Startup
{
// 忽略代碼
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
Console.WriteLine($"01 ConfigureServices");
}
}
在 Startup 的 ConfigureServices 是依賴注入中最開始呼叫的方法,這也是原生的框架自帶的方法
IHostBuilder 的 ConfigureServices 擴展方法
var hostBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseTestServer(); //關鍵是多了這一行建立TestServer
})
.ConfigureServices(collection => Console.WriteLine($"02 ConfigureServices Delegate"))
在 IHostBuilder 的 ConfigureServices 擴展方法將會在 Startup 的 ConfigureServices 方法執行完成之后呼叫,因此如果只使用原生的依賴注入,可以在此方法進行覆寫,也就是如果沒有使用 Autofac 框架,只使用原生的框架,可以在集成測驗,在此方法注入測驗的型別
Startup 的 ConfigureContainer 方法
public class Startup
{
// 忽略代碼
public void ConfigureContainer(ContainerBuilder builder)
{
Console.WriteLine($"03 ConfigureContainer");
builder.RegisterModule(new FooModule());
}
}
可以看到 public void ConfigureContainer(ContainerBuilder builder) 方法的呼叫在 ConfigureServices 方法之后,在 Autofac 也通過此機制實作代替原生的依賴注入功能,也通過此方法從原生的注入獲取依賴
關于 Autofac 的實際邏輯,請參閱下文
FakeAutofacServiceProviderFactory 的 CreateServiceProvider 方法
在如上代碼,咱撰寫了 FakeAutofacServiceProviderFactory 用于替換 AutofacServiceProviderFactory 型別,在 FakeAutofacServiceProviderFactory 的 CreateServiceProvider 方法將會在呼叫 ConfigureContainer 之后執行
class FakeAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
public FakeAutofacServiceProviderFactory(
ContainerBuildOptions containerBuildOptions = ContainerBuildOptions.None,
Action<ContainerBuilder>? configurationActionOnBefore = null,
Action<ContainerBuilder>? configurationActionOnAfter = null)
{
_configurationActionOnAfter = configurationActionOnAfter;
AutofacServiceProviderFactory =
new AutofacServiceProviderFactory(containerBuildOptions, configurationActionOnBefore);
}
private AutofacServiceProviderFactory AutofacServiceProviderFactory { get; }
private readonly Action<ContainerBuilder>? _configurationActionOnAfter;
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
return AutofacServiceProviderFactory.CreateBuilder(services);
}
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
Console.WriteLine($"04 FakeAutofacServiceProviderFactory");
_configurationActionOnAfter?.Invoke(containerBuilder);
return AutofacServiceProviderFactory.CreateServiceProvider(containerBuilder);
}
}
在以上的 CreateServiceProvider 方法將會在 Startup 的 ConfigureContainer 方法之后執行,如上面代碼,按照上面代碼,將會執行 _configurationActionOnAfter 委托
因此下一個執行的就是傳入的委托
IHostBuilder? hostBuilder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseTestServer(); //關鍵是多了這一行建立TestServer
})
.ConfigureServices(collection => Console.WriteLine($"02 ConfigureServices Delegate"))
// 使用 auto fac 代替默認的 IOC 容器
.UseServiceProviderFactory(new FakeAutofacServiceProviderFactory(configurationActionOnAfter:
builder =>
{
Console.WriteLine($"05 ConfigurationActionOnAfter");
builder.RegisterModule<TestModule>();
}));
也就是如上代碼的 ConfigurationActionOnAfter 委托
但盡管 FakeAutofacServiceProviderFactory 的 CreateServiceProvider 在 Startup 的 ConfigureContainer 方法之后執行,實際上很多開發者不會在 Startup 的 ConfigureContainer 方法完成注冊,而是在 ConfigureContainer 里面初始化模塊,如上面代碼,在業務邏輯注冊的模塊的初始化還沒被呼叫,只有在實際的 ContainerBuilder 呼叫 Build 方法,才會執行模塊的 Load 方法
因此下一個呼叫就是業務邏輯注冊的模塊
FooModule 的 Load 方法
按照 Autofac 的定義,在 ConfigureContainer 的 Build 方法里面,才會執行模塊的初始化,呼叫 Load 方法
class FooModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
Console.WriteLine($"06 FooModule");
builder.RegisterType<Foo>().As<IFoo>();
}
}
在 Autofac 里面,將會按照模塊注冊的順序,呼叫模塊的 Load 方法,如上面代碼,可以看到 TestModule 在最后被注冊,因此將會最后執行
TestModule 的 Load 方法
在上面代碼 TestModule 是最后注冊到 Autofac 的模塊,也就是 TestModule 將會最后被執行
class TestModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
Console.WriteLine($"07 TestModule");
builder.RegisterType<TestFoo>().As<IFoo>();
}
}
如上面代碼,在 TestModule 注入的測驗型別,將會替換業務代碼的實際型別
Autofac 接入的方法
通過上面的方法呼叫順序,大家也可以了解為什么集成測驗的代碼這樣寫就有效果,更深入的邏輯是 Autofac 的設計,為什么可以讓 Autofac 框架可以接入到 ASP.NET Core 應用里面,我在此前可一直都是在 WPF 框架使用的,這個問題其實很簡單,所有的 dotnet 專案,無論是 ASP.NET Core 還是 WPF 等,都是相同的 dotnet 邏輯,裝配方式都相同,只是頂層業務邏輯實作方法有所不同,因此只需要加一點適配邏輯就能通用
從上面專案安裝的 NuGet 包可以看到,安裝了 Autofac.Extensions.DependencyInjection 庫就是提供 Autofac 與 dotnet 通用依賴注入框架鏈接的功能,而 ASP.NET Core 原生的框架就是基于 dotnet 通用依賴注入框架,因此就能將 Autofac 接入到 ASP.NET Core 應用
在 UseServiceProviderFactory 方法里面,將會執行 ASP.NET Core 框架的依賴注入容器相關方法,此方法注入的 IServiceProviderFactory 帶泛形的型別,將可以支持在 Startup 方法里面添加 ConfigureContainer 方法,引數就是 IServiceProviderFactory 的泛形
如加入了 FakeAutofacServiceProviderFactory 型別,此型別繼承了 IServiceProviderFactory<ContainerBuilder> 介面,也就是 IServiceProviderFactory 的 泛形 是 ContainerBuilder 型別,因此可以在 Startup 的 ConfigureContainer 方法引數就是 ContainerBuilder 型別
public class Startup
{
// 忽略代碼
public void ConfigureContainer(ContainerBuilder builder)
{
}
}
而 ConfigureContainer 將會被 Microsoft.AspNetCore.Hosting.GenericWebHostBuilder 進行呼叫,在 GenericWebHostBuilder 的呼叫順序是先呼叫 ConfigureServices 再呼叫 對應的 ConfigureContainer 方法
在 Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider 方法就是實際創建容器的方法,這個方法里面,將會先呼叫完成 ConfigureServices 的配置,然后再呼叫 ConfigureContainer 的配置,代碼如下
public class HostBuilder : IHostBuilder
{
private void CreateServiceProvider()
{
// 忽略代碼
var services = new ServiceCollection();
foreach (Action<HostBuilderContext, IServiceCollection> configureServicesAction in _configureServicesActions)
{
configureServicesAction(_hostBuilderContext, services);
}
object containerBuilder = _serviceProviderFactory.CreateBuilder(services);
foreach (IConfigureContainerAdapter containerAction in _configureContainerActions)
{
containerAction.ConfigureContainer(_hostBuilderContext, containerBuilder);
}
_appServices = _serviceProviderFactory.CreateServiceProvider(containerBuilder);
}
}
此時的 _serviceProviderFactory 將會是注入的 FakeAutofacServiceProviderFactory 型別,將會呼叫對應的 CreateBuilder 方法,也就是如下代碼將會呼叫
class FakeAutofacServiceProviderFactory : IServiceProviderFactory<ContainerBuilder>
{
// 忽略代碼
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
return AutofacServiceProviderFactory.CreateBuilder(services);
}
}
在 HostBuilder 的 _configureContainerActions 委托呼叫 ConfigureContainer 的邏輯,實際就是 Startup 型別里面定義的 ConfigureContainer 方法
因此就是先呼叫 Startup 型別和 IHostBuilder 的 ConfigureServices 方法,然后再呼叫 ConfigureContainer 方法
在 Autofac 的 AutofacServiceProviderFactory 在 CreateBuilder 方法就可以拿到了原生注冊的所有型別,因為在呼叫 CreateBuilder 之前已經完成了所有的原生邏輯
在 AutofacServiceProviderFactory 的 CreateBuilder 方法將會先創建 ContainerBuilder 物件,然后呼叫 Populate 方法,從原生的 IServiceCollection 獲取注冊的型別,重新放到 ContainerBuilder 容器
public ContainerBuilder CreateBuilder(IServiceCollection services)
{
var builder = new ContainerBuilder();
builder.Populate(services);
_configurationAction(builder);
return builder;
}
上面代碼的 ContainerBuilder 是 Autofac 框架的,而 Populate 是擴展方法,和 AutofacServiceProviderFactory 都是在 Autofac.Extensions.DependencyInjection 庫提供的,通過此擴展方法和 AutofacServiceProviderFactory 即可實作 Autofac 和 dotnet 原生接入,在 Populate 方法從 dotnet 原生拿到注冊的型別,放入到 Autofac 的 ContainerBuilder 里,這樣所有之前使用 dotnet 原生注入的型別就可以在 Autofac 拿到
public static void Populate(
this ContainerBuilder builder,
IEnumerable<ServiceDescriptor> descriptors,
object lifetimeScopeTagForSingletons = null)
{
if (descriptors == null)
{
throw new ArgumentNullException(nameof(descriptors));
}
builder.RegisterType<AutofacServiceProvider>().As<IServiceProvider>().ExternallyOwned();
builder.RegisterType<AutofacServiceScopeFactory>().As<IServiceScopeFactory>();
Register(builder, descriptors, lifetimeScopeTagForSingletons);
}
以上的 IEnumerable<ServiceDescriptor> 就是 IServiceCollection 型別的物件,實際代碼是 Register 里面拿到注冊的型別,重新放入到 Autofac 里
private static void Register(
ContainerBuilder builder,
IEnumerable<ServiceDescriptor> descriptors,
object lifetimeScopeTagForSingletons)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
builder
.RegisterGeneric(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons);
}
else
{
builder
.RegisterType(descriptor.ImplementationType)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons);
}
}
else if (descriptor.ImplementationFactory != null)
{
var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) =>
{
var serviceProvider = context.Resolve<IServiceProvider>();
return descriptor.ImplementationFactory(serviceProvider);
})
.ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons)
.CreateRegistration();
builder.RegisterComponent(registration);
}
else
{
builder
.RegisterInstance(descriptor.ImplementationInstance)
.As(descriptor.ServiceType)
.ConfigureLifecycle(descriptor.Lifetime, null);
}
}
}
上面代碼拿到的 ServiceDescriptor 就是在原生框架里面的注入型別的定義,可以看到這些都重新放到 Autofac 的容器里面
這就是為什么 Autofac 能拿到在 ASP.NET Core 框架里面其他框架注入的型別的代碼
在 HostBuilder 的 CreateServiceProvider 方法最后就是呼叫 IServiceProviderFactory 的 CreateServiceProvider 方法回傳實際的容器
也就是呼叫了 Autofac 的 CreateServiceProvider 方法,代碼如下
public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder)
{
if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder));
var container = containerBuilder.Build(_containerBuildOptions);
return new AutofacServiceProvider(container);
}
可以看到本質就是呼叫了 ContainerBuilder 的 Build 方法,而在 Build 方法里面,才會初始化 Autofac 的模塊,因此在 FakeAutofacServiceProviderFactory 的 CreateServiceProvider 方法里面添加的代碼,是不會在具體業務模塊的初始化模塊呼叫之前被呼叫,但在 Autofac 里面,模塊的初始化順序是模塊加入 Autofac 的順序,因此可以在 FakeAutofacServiceProviderFactory 里面再加入測驗的模塊,測驗的模塊將會是最后加入的模塊,也就是將會最后被執行
因此想要在接入 Autofac 框架覆寫業務邏輯注冊的型別,就需要在 Autofac 里面注冊一個測驗使用的模塊,要求這個模塊最后注冊,然后在此模塊里面進行注冊型別,這樣就可以讓測驗模塊注冊的型別是最后注冊的,覆寫原有的型別,而想要讓測驗模塊最后注冊,就需要自己實作一個繼承 IServiceProviderFactory<ContainerBuilder> 的型別,才能在 AutofacServiceProviderFactory 的 CreateServiceProvider 方法呼叫之前注冊模塊
雖然我很喜歡使用 Autofac 框架,但是我覺得在接入 ASP.NET Core 時,沒有很好加入測驗的機制,而讓開發者需要自己理解底層的邏輯才能進行注冊測驗的型別
這里也需要給 dotnet 的設計點贊,在一開始的 ASP.NET Core 選擇依賴注入框架時,選擇的是 dotnet 通用依賴注入框架,而 dotnet 通用依賴注入框架最底層的是使用最初的裝配器介面,在 C# 語言里面介面的定義是最通用的,介面只約束而不定義,通過這一套傳承的定義,可以讓 10 多年前的 Autofac 框架依然可以跑在現代的應用里面
這 10 多年也不是 Autofac 啥都不做,上面的說法只是為了說明 dotnet 的兼容性特別強和最初的 dotnet 設計大佬的強大
本文的實作方法,雖然代碼很少,但要理解 dotnet 的依賴注入和 ASP.NET Core 的依賴注入使用,和 Autofac 的接入方法,看起來就是 Autofac 的接入機制其實沒有考慮全,當然,也許是我的技術不夠,也許有更好的實作方法,還請大佬們教教我
代碼
本文所有代碼放在 github 和 gitee 歡迎小伙伴訪問
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/285372.html
標籤:.NET Core
