When using MediatR and a single controller per endpoint the controller is beyond thin; it is micro.

With a base controller that looks like

  public class BaseController<TRequest, TResponse> : Controller
    where TRequest : IRequest<TResponse>
    where TResponse : BaseResponse
  {
    private IMediator _mediator;

    protected IMediator Mediator => _mediator ?? (_mediator = HttpContext.RequestServices.GetService<IMediator>());

    protected virtual async Task<IActionResult> Send(TRequest aRequest)
    {
      TResponse response = await Mediator.Send(aRequest);

      return Ok(response);
    }
  }

The specific controller becomes nothing more than a place to define your route, http verb and the type of the request.

  [Route("api/weatherForecast")]
  public class GetWeatherForecastsController : BaseController<GetWeatherForecastsRequest, GetWeatherForecastsResponse>
  {
    public async Task<IActionResult> Get(GetWeatherForecastsRequest aRequest) => await Send(aRequest);
  }

See these micro controllers utilized in the timewarp-blazor template

References:
Jimmy Bogard put your controllers on a diet
Steve Ardalis Smith
Jason Taylor

Tags: dotnetcore, MediatR, Mediator