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

posted @ 2020-08-03 12:25  沉迷代码的萌新  阅读(1249)  评论(1编辑  收藏  举报