Я пытаюсь создать универсальный обработчик запросов c, используя библиотеку MediatR (v8). Давайте перейдем к коду: во-первых, у меня есть абстрактный класс запросов, подобный этому:
public abstract class Query<TQueryResult> : IRequest<TQueryResult>
{
public Guid Id { get; } = Guid.NewGuid();
public DateTime Timestamp { get; }
protected Query()
{
Timestamp = DateTime.Now;
}
}
Из соответствующего обработчика запросов я хотел бы вернуть объект-оболочку Result
, который выглядит следующим образом:
public class Result<T>
{
public T Payload { get; }
public string FailureReason { get; }
public bool IsSuccess => FailureReason == null;
public Result(T payload)
{
Payload = payload;
}
public Result(string failureReason)
{
FailureReason = failureReason;
}
public static Result<T> Success(T payload)
=> new Result<T>(payload);
public static Result<T> Failure(string reason)
=> new Result<T>(reason);
public static implicit operator bool(Result<T> result) => result.IsSuccess;
}
И, наконец, что не менее важно, давайте посмотрим на обработчик запросов:
public abstract class AbstractQueryHandler<TQuery, TQueryResult, TResultValue> : IRequestHandler<TQuery, TQueryResult>
where TQuery : Query<TQueryResult>
where TQueryResult : class
{
public Task<TQueryResult> Handle(TQuery request, CancellationToken cancellationToken)
{
try
{
return HandleQuery(request);
}
catch (Exception e)
{
return Task.FromResult(Result<TResultValue>.Failure(GetFailureMessage(e)) as TQueryResult);
}
}
public abstract Task<TQueryResult> HandleQuery(TQuery request);
private static string GetFailureMessage(Exception e)
{
return "There was an error while executing query: \r\n" + e.Message;
}
}
Если честно, я не доволен этим решением из-за трех параметров типа, которые у меня есть в обработчик запросов. Давайте посмотрим некоторые соответствующие тесты, чтобы выявить мои опасения по поводу. Сначала объекты помощника по тестированию:
public class ExampleDto
{
public string Name { get; set; }
}
public class BasicQuery : Query<Result<ExampleDto>>
{
}
public class BasicQueryHandler : AbstractQueryHandler<BasicQuery, Result<ExampleDto>, ExampleDto>
{
public override Task<Result<ExampleDto>> HandleQuery(BasicQuery request)
{
return Task.FromResult(Result<ExampleDto>.Success(new ExampleDto() { Name = "Result Name" }));
}
}
А затем тест:
[Fact]
public async Task GivenBasicQuery_whenHandle_thenSuccessResultWithPayload()
{
var handler = new BasicQueryHandler();
var result = await handler.Handle(new BasicQuery(), CancellationToken.None);
Check.That(result.IsSuccess).IsTrue();
Check.That(result.Payload.Name).IsEqualToValue("Result Name");
}
Как вы можете видеть в BasicQueryHandler
, при объявлении трех типов существует некоторое дублирование а именно <BasicQuery, Result<ExampleDto>, ExampleDto>
. Это кажется мне подозрительным. Я также попробовал много других возможностей, проверяя статьи и вопросы и ответы SO на inte rnet, но не смог придумать более чистого решения. Что я делаю неправильно? Можно ли уменьшить количество параметров типа (обработчик запросов) до 2? Заранее спасибо за помощь!