Asp.Net Core 3.0以上,不再能通過修改Starup.ConfigureServices返回值(IServiceProvider),所以只能呼叫IHostBuilder.UseServiceProviderFactory修改最外層的IServiceProviderFactory,達到替換DI容器的目的。
流程是IHostBuilder.UseServiceProviderFactory->IHostBuilder.ConfigureServices->Starup.ConfigureServices,而且IHostBuilder.UseServiceProviderFactory不支援依賴注入,所以只能例項化了,不能取巧的IHostBuilder.ConfigureServices內註冊IServiceProviderFactory
配置Windsor註冊模組
public interface IWindsorContainerModule
{
void Configure(WindsorContainer container);
}
這塊不支援依賴注入,詳情參考上文
自定義DI容器
核心模組 WindsorRegistrationHelper.CreateServiceProvider ,引用Nuget Castle.Windsor.MsDependencyInjection。
internal class WindsorContainerFactory : IServiceProviderFactory<IServiceCollection>
{
private WindsorContainer container;
private IServiceCollection services;
public WindsorContainerFactory(IWindsorContainerModule containerModule)
{
container = new WindsorContainer();
containerModule.Configure(container);
}
public IServiceCollection CreateBuilder(IServiceCollection services)
{
this.services = services;
return services;
}
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder)
{
return WindsorRegistrationHelper.CreateServiceProvider(container, services);
}
}
這裡完成將Windsor和MS DI註冊,統一轉換為根節點的IServiceProvider,內部流程獨立走Windsor,對外則是MS DI的流程。
IHostBuilder擴充套件方法
為了呼叫更簡潔易懂,在IHostBuilder上擴充套件一個UseWindsorContainer方法.
public static IHostBuilder UseWindsorContainer<TWindsorContainerModule>(this IHostBuilder hostBuilder, TWindsorContainerModule containerModule)
where TWindsorContainerModule : class, IWindsorContainerModule
{
return hostBuilder
.UseServiceProviderFactory(new WindsorContainerFactory(containerModule))
.ConfigureServices(services =>
{
services.AddSingleton<IWindsorContainerModule, TWindsorContainerModule>();
});
}
編寫示例程式碼
internal class Sample : IWindsorContainerModule
{
public void Configure(WindsorContainer container)
{
Console.WriteLine("IWindsorContainerModule Instance Name:sample");
container.Register(Component.For(typeof(IHelloInterface)).ImplementedBy(typeof(HelloInterface)).LifestyleSingleton());
}
}
public interface IHelloInterface
{
void Show();
}
internal class HelloInterface : IHelloInterface
{
public void Show()
{
Console.WriteLine(nameof(HelloInterface));
}
}
修改Program.CreateHostBuilder
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindsorContainer(new Sample()) //新增
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>();
});
修改Controllers.WeatherForecastController.Get
public IEnumerable<WeatherForecast> Get()
{
Console.WriteLine(_helloInterface.GetType().FullName); //列印介面實際實現,驗證是否代理到Castle.Windsor
_helloInterface.Show(); //介面呼叫方法
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
後記
感謝Lemon大人的指點~關於 IHostBuilder.UseServiceProviderFactory到IHostBuilder.ConfigureServices的細節和最初的預估差異不小,最早的程式碼實現版本是IHostBuilder.ConfigureServices內註冊了IServiceProviderFactory
如果對於內容有交流和學習的,歡迎加 .Net應用程式框架交流群,群號386092459