在ASP.NET Core中的中间件中注入服务

问题描述:

我想基于HTTP标头值注入服务.所以我有2个类-DbDataProvider和InMemDataProvider,它们都是从IDataProvider实现的.每当进行API调用时,客户端都会通过标头,该标头确定是DbDataProvider是必需的还是InMemDataProvider是必需的.我该如何实现?简而言之,我需要在中间件之一的ServiceCollection中注入服务.有可能吗?

I want to inject a service based on the HTTP header value. So I have 2 classes - DbDataProvider and InMemDataProvider, both are implemented from IDataProvider. Whenever an API call is made, a header is passed by the client which determines whether DbDataProvider is required or InMemDataProvider is required. How do I achieve that? So in short I need to inject service in the ServiceCollection in one of the middlewares. Is that possible?

问题是在Startup类的ConfigureService方法中,我无法获取HttpContext.我已经编写了一个中间件,可以使用它来获取HTTP上下文,但是如何在其中注入服务?

The problem is that in the ConfigureService method in Startup class I cannot get the HttpContext. I have written a middleware using which I am able to get the HTTP Context but how do I inject a Service there?

没有简单或干净的方法可以做到这一点.您不能在ConfigureServices方法之外修改IServiceCollection.但是即使可以,它也没有用,因为容器已经在调用Configure之前构建.

There is no easy or clean way to do this. You can't modify the IServiceCollection outside of the ConfigureServices method. But even if you could, it's of no use, because the container has already been built before Configure is being called.

您可以做的是创建一个工厂类并将其注册为作用域.

What you could do is create a factory class and register it as scoped.

public interface IDataProviderFactory
{
    bool UseInMemoryProvider { get; set; }
    IDataProvider Create();
}

public class DataProviderFactory : IDataProviderFactory
{
    private readonly IServiceProvider provider;

    public bool UseInMemoryProvider { get; set; }

    public DataProviderFactory(IServiceProvider provider) 
    {
        this.provider = provider;
    }

    public IDataProvider Create()
    {
        if(UseInMemoryProvider) 
        {
            return provider.RequestService<InMemoryDataProvider>();
        }

        return provider.RequestService<DbDataProvider>();
    }
}

然后在您的中间件中:

public class MyMiddleware
{
    public void Invoke(HttpContext context) 
    {
        var dataProviderFactory = context.RequestServices.RequestService<IDataProviderFactory>();

        // Your logic here
        if(...)
        {
            dataProviderFactory.UseInMemoryStore = true;
        } 
    }
}

以及您的控制器/服务中:

and in your controller/services:

public class MyController : Controller 
{
    private readonly IDataProvider dataProvider;

    public MyController(IDataProviderFactory dataProviderFactory)
    {
        dataProvider = dataProviderFactory.Create();
    }
}