Если ваш обработчик команд зависит от большего количества информации, чем он получил в команде, чтобы воздействовать на него, то вы не предоставляете достаточно информации в команде; в этом случае, если вам нужно применить операцию, основанную на ModelState, вам нужно будет включить и передать ModelState в команду.
Независимо от того, сможете ли вы сделать это эффективно или нет, я бы более глубоко позвонил под вопросом необходимость использования MediatR или какой-либо другой формы командной шины здесь, в первую очередь; вы синхронно выполняете операцию и ожидаете ответа, плюс обработчик пытается выполнить много действий (получение хранилища, проверка модели, сохранение хранилища), поэтому, хотя вы сократили объем кода в контроллере, вы на самом деле я только переместил его в новое место, которое все еще тесно связано, и теперь просто запутывает зависимости контроллера.
Поведение, которое вы упаковали в Controller -> Command -> Handler и обратно, похоже на он также будет обслуживаться какой-либо формой провайдера (или, вероятно, несколькими провайдерами), введенными в ваш контроллер посредством внедрения зависимости; вы можете использовать интерфейс для сохранения гибкости своего кода и очевидных зависимостей, при этом уменьшая грубую работу, выполняемую внутри самого кода контроллера, чтобы помочь поддерживать его в чистоте, вместо этого вызывая (все еще абстрагированные) описательные методы, которые express намерение.
Обновление 1 Это не полностью концептуализированный пример, но, надеюсь, иллюстративный. Если вы хотите использовать командную шину для сквозных задач, для этого еще есть место, но только после того, как вы выполнили проверку ввода, et c. Больше не нужно передавать состояние контроллера.
public class YourController : Controller
{
private readonly ILogger<YourController> _logger;
private readonly IModelPatcher<SomeInput, SomeOutput> _modelPatcher;
private readonly IWriteRepository<SomeOutput> _writeRepository;
public YourController(ILogger<YourController> logger, IModelPatcher<SomeInput, SomeOutput> modelPatcher, IWriteRepository<SomeOutput> writeRepository)
{
_logger = logger;
_modelPatcher = modelPatcher;
_writeRepository = writeRepository;
}
[HttpPatch("{valueToReplaceId}")]
public IActionResult PartiallyUpdateValueToReplace(int valueToReplaceId, JsonPatchDocument<SomeInput> patchDoc)
{
if (patchDoc == null) return BadRequest();
var result = _modelPatcher.ApplyPatch(patchDoc, valueToReplaceId);
if (result == null) return NotFound();
if (!TryValidateModel(result)) return ValidationProblem(ModelState);
// var mapToDto = _mapper.Map(result); // maybe even here, before the repo...
_writeRepository.Update(result); // <-- This could be a command! Model is ready, validation is done.
return NoContent();
}
}
public class SomeInput { }
public class SomeOutput { }
public interface IModelPatcher<in TInput, out TResult>
{
TResult ApplyPatch(JsonPatchDocument<TInput> inputModel, int value);
}
public class SomeInputModelPatcher : IModelPatcher<SomeInput, SomeOutput>
{
private readonly IReadRepository<Something> _repository;
public SomeInputModelPatcher(IReadRepository<Something> repository)
{
_repository = repository;
}
public SomeOutput ApplyPatch(JsonPatchDocument<SomeInput> inputModel, int value)
{
// Do the patch related work
return new SomeOutput();
}
}