在Startup外添加服务

Sib*_*Guy 4 .net asp.net-core

有没有办法在Startup类之外添加服务.换句话说,我们可以在Startup之外访问当前请求的ServiceCollection吗?

当你有一个创建子容器的工厂,根据输入参数(即Web Api的情况下的查询参数)注册附加服务然后解析特定服务时,IoC中有一个典型的场景.我曾经使用的每个IoC工具都支持这个工作流程,但是我没有看到通过ASP.NET Core Dependency Injection实现这一目的的方法.似乎我可以找到的每个示例都在Startup类中添加了服务.

Joe*_*kes 6

即使我对自己错误地使用IOC容器作为工厂方法或存储库感到内疚.它没有为此做出,并且是一种反模式.

因此:Microsoft试图通过以下方式防止这种情况:在IServiceCollection(构建器)和IServiceProvider(解析程序)中拆分IOC容器.

Microsoft.AspNetCore.Hosting.StartupBase:

public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
  return services.BuildServiceProvider();
}
Run Code Online (Sandbox Code Playgroud)

变成了IServiceCollection一个IServiceProvider.

默认实现不会动态添加新的依赖项.

如果你想要这个,你应该使用另一个Container,或者让你自己的实现回退到默认容器.

为什么微软会这样做

我不确定这背后的确切原因是什么.但我会列举一些:

  • 添加新条目通常很重要,因为它们必须进行编译.(这些lambda的真正动态创作可能导致内存问题,不要担心你可能不会有这个问题)
  • 如果更改实现,则不知道现有实例会发生什么(如果预期其他类型,则会导致奇怪的运行时问题).
  • 如果您能够使用string key名称(如工厂方法)解析.然后,您的代码与此密钥的注册紧密相关.(而不是松散耦合).

DIY伪解决方案

public class MyServiceProviderWrapper : IServiceProvider
{
    private readonly IServiceProvider _msDefaultProvider;

    public MyServiceProviderWrapper(IServiceProvider msDefaultProvider)
    {
        _msDefaultProvider = msDefaultProvider;
    }
    public object GetService(Type serviceType)
    {
        //I can return my own implementation here:
        //If(myRegistrations.contains(serviceType)) myRegistrations.get(serviceType)

        //fallback to microsofts default container:
        return _msDefaultProvider.GetService(serviceType);
    }
}


public class MyStartup : Microsoft.AspNetCore.Hosting.StartupBase
{
    public override IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // We build the di container. 
        // we could save MyServiceProviderWrapper on a static property for later use. (or  turn itself into a singleton).
        return new MyServiceProviderWrapper(base.ConfigureServices(services));
    }
 }
Run Code Online (Sandbox Code Playgroud)