5

I created a request exception handler with known types as below and the exception is handled. The only examples I found are doing it this way.

using MediatR.Pipeline;
using Microsoft.Extensions.Logging;
using MyPortal.Application.Common.Models;
using MyPortal.Application.MyCommands.Commands.CompleteMyCommand;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyPortal.Application.Common.Behaviors
{
    public class RequestGenericExceptionHandler : IRequestExceptionHandler<MyCommand, Result>
    {
        private readonly ILogger<MyCommand> _logger;

        public RequestGenericExceptionHandler(ILogger<MyCommand> logger)
        {
            _logger = logger;
        }

        public async Task Handle(MyCommand request,
            Exception exception,
            RequestExceptionHandlerState<Result> state,
            CancellationToken cancellationToken)
        {
            var name = typeof(MyCommand).Name;
            _logger.LogError("MyPortal Request Exception {@Request}",
                    name, exception.Message, request);
        }
    }
}

When I try to use something like this it's not handled:

    public class RequestGenericExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
        where TRequest : IRequest<TResponse>
    {
        private readonly ILogger<TRequest> _logger;

        public RequestGenericExceptionHandler(ILogger<TRequest> logger)
        {
            _logger = logger;
        }

        public async Task Handle(TRequest request,
            Exception exception,
            RequestExceptionHandlerState<TResponse> state,
            CancellationToken cancellationToken)
        {
            var name = typeof(TRequest).Name;
            _logger.LogError("MyPortal Request Exception {@Request}",
                    name, exception.Message, request);
        }
    }

I'm using .Net Core 3.1, Mediator 8.0.1, and MediatR.Extensions.Microsoft.DependencyIntjection 8.0.0 and this is my only dependency injection:

            services.AddMediatR(Assembly.GetExecutingAssembly());
Progman
  • 16,827
  • 6
  • 33
  • 48
DaveG
  • 121
  • 1
  • 6

2 Answers2

7

I needed to make these changes:

public class RequestGenericExceptionHandler<TRequest, TResponse, TException> : IRequestExceptionHandler<TRequest, TResponse, TException>
    where TException : Exception {

    public async Task Handle(TRequest request,
        TException exception,
        RequestExceptionHandlerState<TResponse> state,
        CancellationToken cancellationToken) {}
}

This line is only needed if not using MediatR.Extensions.Microsoft.DependencyIntjection:

services.AddTransient(typeof(IRequestExceptionHandler<,,>), typeof(RequestGenericExceptionHandler<,,>));

Reference: https://github.com/jbogard/MediatR/issues/486

double-beep
  • 5,031
  • 17
  • 33
  • 41
DaveG
  • 121
  • 1
  • 6
  • This was really, really helpful for me. There are no good articles online that I could find which explains this concept. And the code on Github is not complete. – jason.kaisersmith Mar 25 '21 at 16:13
  • Here's some **inspiration for the** *exception handling* **implementation code**: https://stackoverflow.com/a/74699898/495455 – Jeremy Thompson Dec 15 '22 at 00:42
0

something like this should work. Also if you want to return a generic response for exception you can make all your response class implement same interface and then return a generic one

public class GenericRequestExceptionHandler<TRequest, TResponse, TException> : IRequestExceptionHandler<TRequest, TResponse, TException>
    where TRequest : IRequest
    where TResponse : Result
    where TException : Exception
{
    private readonly ILogger<TRequest> _logger;
    public GenericRequestExceptionHandler(ILogger<TRequest> logger)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }
    public async Task Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken = new CancellationToken())
    {
        _logger.LogError(exception, $"Error occurs on handling {nameof(TRequest)}");
        await Task.Run(() => state.SetHandled((TResponse)Result.Failure(new string[] { exception.Message })));
    }
}