选择有条件的注入实例

Selecting Injected Instance with Conditional

我有几个 类 从一个接口继承而来。我希望根据条件在控制器中加载和使用所需的服务。

控制器

public class GatewayController
{
    private readonly IAction action;

public GatewayController(IAction action)
{
    this.action = action;
}
[HttpPost("gateway")]
public async Task<ApiResult> Gateway(GatewayRequest gatewayRequest, CancellationToken cancellationToken)
{
    try
    {
        var comId = gatewayRequest.CommandId;
        switch (comId)
        {
            case (int) GuaranteeItemStatus.End:
                return await action.Perform(gatewayRequest, cancellationToken); //must be use EndActionService

            case (int) GuaranteeItemStatus.SendProduct:
                return await action.Perform(gatewayRequest, cancellationToken);  //must be use SendProductActionService
            default:
                return null;
        }
    }
    catch (Exception ex)
    {
        return ApiResult.ToErrorModel("error");
    }

}

}

父接口:

 public interface IAction
    {
        Task<ApiResult> Perform(GatewayRequest gatewayRequest, CancellationToken cancellationToken);
    }

服务:

1-SendProductActionService:

 public class SendProductActionService:IAction
    {
        public async Task<ApiResult> Perform(GatewayRequest gatewayRequest, CancellationToken cancellationToken)
        {
            return ApiResult.ToSuccessModel("SendProduct");
        }
    }

2-EndActionService:

 public class EndActionService:IAction
    {
        public async Task<ApiResult> Perform(GatewayRequest gatewayRequest, CancellationToken cancellationToken)
        {
            return ApiResult.ToSuccessModel("EndAction");
        }
    }

可以注册并注入包含您所有 IActionIEnumerable

首先,要确定哪个 IAction 对哪个命令作出反应,您可以添加一个 CommandId 属性:

public interface IAction
{
    int CommandId { get; }
}

public class SendProductActionService : IAction
{
    public int CommandId => (int)GuaranteeItemStatus.SendProduct;
}

public class EndActionService : IAction
{
    public int CommandId => (int)GuaranteeItemStatus.End;
}

在您的 Startup.cs 中,您注册了所有操作:

services.AddScoped<IAction, SendProductActionService>();
services.AddScoped<IAction, EndActionService>();

然后在您的控制器中,注入所有 IAction,并在需要时 select 注入适当的:

public class GatewayController
{
    // map the command ID to the proper IAction
    private readonly Dictionary<int, IAction> actions;

    // inject all the services registered that implement IAction
    public GatewayController(IEnumerable<IAction> actions)
    {
        this.actions = actions.ToDictionary(_ => _.CommandId);
    }
    
    [HttpPost("gateway")]
    public async Task<ApiResult> Gateway(GatewayRequest gatewayRequest, CancellationToken cancellationToken)
    {
        // find the appropriate IAction
        if (!actions.TryGetValue((int)gatewayRequest.CommandId, out var action)
            return BadRequest();
        
        return await action.Perform(gatewayRequest, cancellationToken);  
    }
}

在你的startup.cs中:

services.AddScoped<SendProductActionService>();
services.AddScoped<EndActionService>();
services.AddScoped<Func<GuaranteeItemStatus, IAction>>(serviceProvider => status =>
{
    switch (status)
    {
        case GuaranteeItemStatus.SendProduct:
            return serviceProvider.GetService<SendProductActionService>();
        case GuaranteeItemStatus.End:
            return serviceProvider.GetService<EndActionService>();
        default:
            throw new InvalidOperationException();
    }
});

您的控制器应该与此类似:

public class GatewayController
{
    private readonly Func<GuaranteeItemStatus, IAction> actionProvider;

    public GatewayController(Func<GuaranteeItemStatus, IAction> actionProvider)
    {
        this.actionProvider = actionProvider;
    }

    [HttpPost("gateway")]
    public async Task<ApiResult> Gateway(GatewayRequest gatewayRequest, CancellationToken cancellationToken)
    {
        try
        {
            return await actionProvider((GuaranteeItemStatus)gatewayRequest.CommandId)
                .Perform(gatewayRequest, cancellationToken);
        }
        catch (Exception ex)
        {
            return ApiResult.ToErrorModel("error");
        }
    }
}