MediatR Result Wrapper - ChrispyPeaches/FocusFriends GitHub Wiki

MediatrResultWrapper <T>

The MediatrResultWrapper class is a wrapper allowing API MediatR features to communicate status codes and error messages to the controller calling the feature.

Properties

HttpStatusCode

  • Type: HttpStatusCode
  • Default Value: null
  • Description: Holds the http status code for the result.

Message

  • Type: string
  • Default Value: null
  • Description: Holds a message for the result if applicable (intended for errors).

Data

  • Type: T? (Generic)
  • Default Value: null
  • Description: The data that the result holds if applicable.

Usage Details

Anywhere that you would put the result class (ex: CreateUserResponse ), you would instead use MediatrResultWrapper<T> where T is a class that the wrapper would attach an http status code and message to (ex: MediatrResultWrapper<CreateUserResponse> ). Additionally, you have the option of using this wrapper for the controller responses, or the controller could return an ActionResult using a refit ApiResponse wrapper (this is what is demonstrated in the examples) or something similar.

  • Documentation for ActionResult linked here
  • Docuemntation for ReactiveUI/Refit ApiResponse wrapper linked here

An Implementation Example

MediatR query and response classes

Note: Both of these are inside of FocusCore to share the classes between the App and API
// A query class for a MediatR feature using the MediatrResultWrapper for the response
public class GetUserQuery : IRequest<MediatrResultWrapper<GetUserResponse>>
{
    public string? Auth0Id { get; set; }
	...
}

// The associated response class
public class GetUserResponse
{
    public BaseUser? User { get; set; }
	...
}

Refit Client Method

// The Refit client endpoint. 
// Note: This is using the refit ApiResponse wrapper so that an ActionResult return type can be used by the controller.
// 	 This is the option used in this example, but alternatively you could return using the MediatrResultWrapper
[Get("/User/GetUser")]
Task<ApiResponse<GetUserResponse>> GetUserByAuth0Id(
	GetUserQuery query,
	CancellationToken cancellationToken = default);

API Controller Endpoint

// The associated API endpoint
// This is an example of how it can be used to communicate a response code from the MediatR feature to the controller so that it can log the response and return the appropriate status code
[HttpGet]
[Route("GetUser")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<GetUserResponse>> GetUserByAuth0Id(
    [FromQuery] GetUserQuery query,
    CancellationToken cancellationToken)
{
    MediatrResultWrapper<GetUserResponse> result = new();

    try
    {
        result = await _mediator.Send(query, cancellationToken);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "[500]: Error getting user");
        return StatusCode((int)HttpStatusCode.InternalServerError);
    }

    switch (result.HttpStatusCode)
    {
        case null:
            return StatusCode((int)HttpStatusCode.InternalServerError);
        case HttpStatusCode.OK:
            return Ok(result.Data);
        default:
            _logger.LogError($"[{(int)result.HttpStatusCode}] {result.Message}");
            return StatusCode((int)result.HttpStatusCode);
    }
}

MediatR Feature

Transmitting a success

// Inside of the MediatR feature, the wrapper can be used to transmit a success like this example 
return new()
{
    HttpStatusCode = HttpStatusCode.OK,
    Data = user
};

Transmitting an error

// Or it can be used to transmit an error like it is here
return new()
{
    HttpStatusCode = HttpStatusCode.NotFound,
    Message = $"User not found with Auth0Id: {query.Auth0Id}"
};
⚠️ **GitHub.com Fallback** ⚠️