Как сделать универсальный контроллер для запросов апи с помощью MediatR?
У меня есть контроллер для таблицы с учителями. Если сделать запрос на api/tutors, учителя отправятся в JSON в виде ответа.
Controller
[ApiController]
public sealed class TutorsController : Controller
{
private readonly IMediator mediator;
private readonly IMapper mapper;
public TutorsController(IMediator mediator, IMapper mapper)
{
this.mediator = mediator;
this.mapper = mapper;
}
[HttpGet("api/tutors")]
public async Task<IActionResult> Get([FromQuery] int page = 0, [FromQuery] int size = 30)
{
var getTutorsQuery = new GetTutorsQuery(page, size); // строка с комментарием
var tutors = await mediator.Send(getTutorsQuery);
return Ok(mapper.Map<PageDto<TutorDto>>(tutors));
}
}
GetTutorsQuery
internal sealed class GetTutorsQuery : IRequest<Page<Tutor>>
{
public GetTutorsQuery(long pageNumber, long pageSize)
{
PageNumber = pageNumber;
PageSize = pageSize;
}
public long PageSize { get; }
public long PageNumber { get; }
}
GetStudentsQueryHandler
[UsedImplicitly]
internal sealed class GetStudentsQueryHandler : IRequestHandler<GetTutorsQuery, Page<Tutor>>
{
private readonly ICrudRepository<Tutor> tutorsRepository;
public GetStudentsQueryHandler(ICrudRepository<Tutor> tutorsRepository)
{
this.tutorsRepository = tutorsRepository;
}
public async Task<Page<Tutor>> Handle(GetTutorsQuery request, CancellationToken cancellationToken)
{
return await tutorsRepository.Get(request.PageNumber, request.PageSize);
}
}
Сейчас мне нужно сделать так, чтобы при запросе на api/students и api/lessons также возвращались данные по такому же принципу как у учителей. Можно сделать несколько контроллеров, но тогда будет слишком много повторяющегося кода. Можно ли как-то упростить контроллеры с помощью дженериков?
Пробовал сделать вместо new GetTutorsQuery (Controller, строка с комментарием) сделать new GetQuery<Tutor>. В GetTutorsQuery и GetStudentsQueryHandler заменил все упоминания Tutor на T (ну и в названия классов тоже добавил <T>). Но в таком случае возникает ошибка
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Error constructing handler for request of type MediatR.IRequestHandler`2[SPA.Application.Queri
es.GetQuery`1[SPA.Models.Tutor],SPA.Models.Page`1[SPA.Models.Tutor]]. Register your handlers with the container. See the samples in Gi
tHub for examples.
---> System.InvalidOperationException: No service for type 'MediatR.IRequestHandler`2[SPA.Application.Queries.GetQuery`1[SPA.Mo
dels.Tutor],SPA.Models.Page`1[SPA.Models.Tutor]]' has been registered.
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Ty
pe serviceType)
at MediatR.ServiceFactoryExtensions.GetInstance[T](ServiceFactory factory)
at MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)
--- End of inner exception stack trace ---
at MediatR.Wrappers.HandlerBase.GetHandler[THandler](ServiceFactory factory)
at MediatR.Wrappers.RequestHandlerWrapperImpl`2.<>c__DisplayClass1_0.<Handle>g__Handler|0()
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationT
oken cancellationToken)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationT
oken cancellationToken)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, Cancell
ationToken cancellationToken)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, Cancell
ationToken cancellationToken)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken
cancellationToken)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, RequestHandlerDelegate`1 next, CancellationToken c
ancellationToken)
at SPA.V1.Controllers.V1TutorsController.Get(Int32 page, Int32 size) in C:\Users\aesok\Desktop\tutoraggregator\SPA\V1\Control
lers\V1TutorsController.cs:line 34
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper m
apper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionI
nvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerAct
ionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& is
Completed)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker,
Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isComplete
d)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, I
Disposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, I
Disposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogg
er logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)