dotnet/meditr 最佳实践中的 REST 补丁

XRa*_*cat 7 .net patch .net-core mediatr

我已经使用 PUT/POST 来更新我正在使用的应用程序,到目前为止这一直很简单。现在我正在开发一个 API,它应该公开一种更新数据库中数据的方法,我最初的想法是我可以替换该行(或部分替换它)。由于具有不同数据知识的不同应用程序需要更新,因此我认为使用 PATCH 操作而不是 PUT 可能是一个好主意。

我可以找到一些在控制器中实现更新的玩具示例,但我对此不感兴趣。

我使用与jasontaylordev的 Clean 架构项目中相同的模式(CQRS w. Mediatr),所以我将在我的示例中使用它。

我有两个问题。

  1. 我不喜欢该JsonPatchDocument对象应该到达我的处理程序,但我不知道如何避免这种情况。无法从控制器访问数据库。那么还有其他选择吗?(注意 Automapper 或类似的动态映射库在我正在从事的项目中都不是一个选项)

  2. 如何从客户端应用程序(所有 dotnet 核心项目)构建 JsonPatch 对象。我认为如果我可以在应用程序一中拥有一个具有两个属性Title和的 DTO,Note并且如果Title="test"Note=null,那么它应该替换标题并删除注释,这可能会很简洁。我可以以简单的方式映射到(奇怪的)补丁对象吗?

     [HttpPatch("{id}")]
     public async Task<ActionResult> Update(int id, UpdateTodoItemCommand command)
     {
      if (id != command.Id)
       {
      return BadRequest();
      }
    
     await Mediator.Send(command);
    
     return NoContent();
     }
    
     public class UpdateTodoItemCommand : IRequest
     {
       public int Id { get; set; }
    
       public JsonPatchDocument<TodoItemDto> Todo { get; set; }
     }
    
     public class TodoItemDto
     {
       public string Title { get; set; }
    
       public string Note { get; set; }
     }
    
    
     public class UpdateTodoItemCommandHandler : IRequestHandler<UpdateTodoItemCommand>
     {
       private readonly IApplicationDbContext _context;
    
       public UpdateTodoItemCommandHandler(IApplicationDbContext context)
       {
        _context = context;
       }
    
     public async Task<Unit> Handle(UpdateTodoItemCommand request, CancellationToken cancellationToken)
     {
         var entity = await _context.TodoItems.FindAsync(request.Id);
    
         if (entity == null)
         {
             throw new NotFoundException(nameof(TodoItem), request.Id);
         }
    
         var todoItemDto = new TodoItemDto();
         todoItemDto.Title = entity.Title;
         todoItemDto.Note = entity.Note: 
    
         todoItemDto.Todo.ApplyTo(request.Todo);
    
         entity.Title = todoItemDto.Title;
         entity.Note = todoItemDto.Note;
    
         await _context.SaveChangesAsync(cancellationToken);
    
         return Unit.Value;
     }
    }
    
    Run Code Online (Sandbox Code Playgroud)

小智 3

我遇到了同样的问题,我想出了一个对我有用的解决方案。

在 UpdateTodoItemCommandHandler 类的 Handle 方法中,您将再创建一个 JsonPatchDocument,但类型为 TodoItem(不是 Dto)。然后将操作和 ContractResolver 传输到新的 JsonPatchDocument 对象,您可以修补该对象并将其保存到数据库。像这样的东西:

var entity = await _context.TodoItems.FindAsync(request.Id);

if (entity == null)
{
    throw new NotFoundException(nameof(TodoItem), request.Id);
}    

var todoItemPatch = new JsonPatchDocument<TodoItem>();

foreach (var opr in request.Todo.Operations)
{
    todoItemPatch.Operations.Add(new Operation<TodoItem> 
    { 
        op = opr.op, 
        path = opr.path, 
        value = opr.value 
    });
}

todoItemPatch.ContractResolver = 
request.Todo.ContractResolver;

todoItemPatch.ApplyTo(entity);

await _context.SaveChangesAsync(cancellationToken);
Run Code Online (Sandbox Code Playgroud)