10分鍾 Castle.Windsor 適配 Asp.Net Core 3.0


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);
  }
}

這里完成將WindsorMS 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 ,希望更優雅的實現替換DI容器,現實是這塊是不可以的~

如果對於內容有交流和學習的,歡迎加 .Net應用程序框架交流群,群號386092459


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM