依赖注入ASP.NET Core:注册多个实现

时间:2018-08-17 14:00:07

标签: c# asp.net-core dependency-injection asp.net-core-2.1

我具有以下类结构:

interface IContractService{}

class Service1 : IContractService{}

class Service2 : IContractService{}

class ContractServiceFactory
{
    private readonly IServiceProvider _serviceProvider;
     ContractServiceFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;            
    }
     IContractService GetContractService(string standard)
    {
        // Is it possible to retrieve service by string const???
        return _serviceProvider.GetRequiredService<IContractService>(standard);
    }
}

在服务集合中,我想通过以下方式添加类:

builder.Services.AddScoped<IContractService, ContractService1>("standard1");
builder.Services.AddScoped<IContractService, ContractService2>("standard2");

.net core 2.1是否可能?

3 个答案:

答案 0 :(得分:2)

对于这样复杂的注册,默认的开箱即用DI太简单了。它旨在满足该框架以及基于该框架构建的大多数消费者应用程序的基本需求。

因此默认情况下,您所需的功能不可用。

但是,该框架允许您使用功能良好的首选容器并替换默认容器。

官方文档在此处提供了一个示例

Dependency injection in ASP.NET Core: Default service container replacement

另一种选择可能是将设计更改为更加明确的SOLID

jwtToken

然后您相应地注册服务

interface IContractService{}

interface IContractService1: IContractService{}

interface IContractService2: IContractService{}

class ContractService1 : IContractService1{}

class ContractService2 : IContractService2{}

class ContractServiceFactory {
    private readonly IServiceProvider _serviceProvider;

    public ContractServiceFactory(IServiceProvider serviceProvider) {
        _serviceProvider = serviceProvider;            
    }

    public IContractService GetContractService(string standard) {
        switch(standard) {
            case "standard1" :
                return _serviceProvider.GetRequiredService<IContractService1>();
                break;
            case "standard2" :
                return _serviceProvider.GetRequiredService<IContractService2>();
                break;
            case .....
        }
    }
}

答案 1 :(得分:1)

您可以使用工厂进行操作:

因此,首先您需要定义2个服务:

services.AddScoped<Service1>();
services.AddScoped<Service2>();

services.AddScoped<Func<int, IContractService>>(serviceProvider=> key=>
{
    switch(key)
    {
        case 1:
           return serviceProvider.GetService<Service1>();
        case 2:
           return serviceProvider.GetService<Service2>();
        default:
            throw new Exception("Not valid key");
    }
});

此处是GetService的docs.microsoft,您可以使用某种枚举代替普通的int

之后,在您的控制器中:

public class HomeController:Controller
{

    private readonly Service1 _service1;   

    public HomeController(Func<int, IContractService> serviceProvider)
    {
        _service1 = serviceProvider(1);            
    }

}

答案 2 :(得分:0)

我找到了以下替代方案:

假设我们有一个同时使用两种类型的类:

class Foo
{
    public Foo(IContractService contractService1, IContractService contractService2)
    {
     ...
    }
}

您可以像这样注册服务(无需指定接口):

builder.Services.AddScoped<ContractService1>();
builder.Services.AddScoped<ContractService2>();

然后像这样注册需要它们的类型(以上Foo类的示例):

 builder.Services.AddScoped<Foo>(sp => new Foo(sp.GetService<ContractService1>, sp.GetService<ContractService2>));