API 控制器中的业务逻辑

Business logic in the API controller

我的 ClientsController 中有这个方法:

//POST api/v1/clients
[HttpPost]
public async Task<ActionResult> CreateClient([FromBody] CreateClientDto createClientDto)
{
    await _createClientService.Create(createClientDto.MapToClient());
    return CreatedAtRoute("GetClient", new { clientId = createClientDto.ClientId });
}

如您所见,此方法引用了先前注入的服务。 该服务如下所示:

public class CreateClientServiceImpl : ICreateClientService
{
    private readonly ConfigurationDbContext configurationDbContext;

    public CreateClientServiceImpl(ConfigurationDbContext configurationDbContext)
    {
        this.configurationDbContext = configurationDbContext;
    }

    public async Task Create(Client client)
    {
        await configurationDbContext.Clients.AddAsync(client.ToEntity());
        await configurationDbContext.SaveChangesAsync();
    }
}

问题就出在这里。我将在哪里检查 clientId 是否存在?我认为不在 ICreateClientService 中,因为它会违反单一职责原则规则。我可以创建下一个服务来检查用户是否存在并在控制器方法中使用它,但我认为控制器方法中的逻辑太多了。那我该怎么办?可以肯定的是,ClientId不是增量Id,但也是唯一的。

首先回答这个问题:如果客户端已经存在,您希望您的应用程序如何反应?

此外,您是否知道 SaveChangesAsync() 可以抛出 DbUpdateExceptionDbUpdateConcurrencyException?目前,您不处理这些案例。

一种可能性是引入一个异常,例如 DuplicateClientException 并在您的 CreateClientServiceImpl.Create 方法中抛出该异常,如果该客户端已经存在。 另一种选择是 Create return 是一个 bool,表示创建语句是否成功。如果失败,它可能 return false(一个原因可能是客户端已经存在)。 您还可以 return 一个 Result-object。 Ardelis 有一个库,请参阅 Result,它提供了解决您遇到的问题的方法。

然后您的控制器方法可以处理异常,将方法 return 值转换为您认为合适的值,或者(自动)将 Result 对象转换为正确的状态代码,例如 400 Bad Request.

现在,如果您的主键设置正确,我相信您的代码会 运行 出现异常,并且您的控制器会 return 500 Internal Server Error。如果这是您想要的行为,那么您无需更改任何内容。