Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/MediatR.Examples.Lamar/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private static IMediator BuildMediator(WrappingWriter writer)
scanner.AssemblyContainingType<Ping>();
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
scanner.ConnectImplementationsToTypesClosing(typeof(INotificationHandler<>));
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestExceptionAction<>));
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestExceptionAction<,>));
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestExceptionHandler<,,>));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace MediatR.Examples.ExceptionHandler;

public class CommonExceptionHandler : AsyncRequestExceptionHandler<PingResource, Pong>
public class CommonExceptionHandler : IRequestExceptionHandler<PingResource, Pong, Exception>
{
private readonly TextWriter _writer;

public CommonExceptionHandler(TextWriter writer) => _writer = writer;

protected override async Task Handle(PingResource request,
public async Task Handle(PingResource request,
Exception exception,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace MediatR.Examples.ExceptionHandler.Overrides;

public class CommonExceptionHandler : AsyncRequestExceptionHandler<PingResourceTimeout, Pong>
public class CommonExceptionHandler : IRequestExceptionHandler<PingResourceTimeout, Pong, Exception>
{
private readonly TextWriter _writer;

public CommonExceptionHandler(TextWriter writer) => _writer = writer;

protected override async Task Handle(PingResourceTimeout request,
public async Task Handle(PingResourceTimeout request,
Exception exception,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace MediatR.Examples.ExceptionHandler;

public class LogExceptionAction : IRequestExceptionAction<Ping>
public class LogExceptionAction : IRequestExceptionAction<Ping, Exception>
{
private readonly TextWriter _writer;

Expand Down
75 changes: 0 additions & 75 deletions src/MediatR/Pipeline/IRequestExceptionAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,78 +22,3 @@ public interface IRequestExceptionAction<in TRequest, in TException>
/// <returns>An awaitable task</returns>
Task Execute(TRequest request, TException exception, CancellationToken cancellationToken);
}

/// <summary>
/// Defines the base exception action for a request.
/// You do not need to register this interface explicitly
/// with a container as it inherits from the base
/// <see cref="IRequestExceptionAction{TRequest, TException}" /> interface.
/// </summary>
/// <typeparam name="TRequest">The type of failed request</typeparam>
public interface IRequestExceptionAction<in TRequest> : IRequestExceptionAction<TRequest, Exception>
where TRequest : notnull
{
}

/// <summary>
/// Wrapper class that asynchronously performs an action on a request for base exception
/// </summary>
/// <typeparam name="TRequest">The type of failed request</typeparam>
public abstract class AsyncRequestExceptionAction<TRequest> : IRequestExceptionAction<TRequest>
where TRequest : IRequest
{
async Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request, Exception exception, CancellationToken cancellationToken)
=> await Execute(request, exception, cancellationToken).ConfigureAwait(false);

/// <summary>
/// Override in a derived class for the action logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">Original exception from request handler</param>
/// <param name="cancellationToken">Cancellation token</param>
protected abstract Task Execute(TRequest request, Exception exception, CancellationToken cancellationToken);
}

/// <summary>
/// Wrapper class that synchronously performs an action on a request for specific exception
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public abstract class RequestExceptionAction<TRequest, TException> : IRequestExceptionAction<TRequest, TException>
where TRequest : notnull
where TException : Exception
{
Task IRequestExceptionAction<TRequest, TException>.Execute(TRequest request, TException exception, CancellationToken cancellationToken)
{
Execute(request, exception);
return Task.CompletedTask;
}

/// <summary>
/// Override in a derived class for the action logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">Original exception from request handler</param>
protected abstract void Execute(TRequest request, TException exception);
}

/// <summary>
/// Wrapper class that synchronously performs an action on a request for base exception
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
public abstract class RequestExceptionAction<TRequest> : IRequestExceptionAction<TRequest>
where TRequest : notnull
{
Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request, Exception exception, CancellationToken cancellationToken)
{
Execute(request, exception);
return Task.CompletedTask;
}

/// <summary>
/// Override in a derived class for the action logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">Original exception from request handler</param>
protected abstract void Execute(TRequest request, Exception exception);
}
81 changes: 0 additions & 81 deletions src/MediatR/Pipeline/IRequestExceptionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,84 +24,3 @@ public interface IRequestExceptionHandler<in TRequest, TResponse, in TException>
/// <returns>An awaitable task</returns>
Task Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken);
}

/// <summary>
/// Defines the base exception handler for a request and response
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public interface IRequestExceptionHandler<in TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse, Exception>
where TRequest : notnull
{
}

/// <summary>
/// Wrapper class that asynchronously handles a base exception from request
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public abstract class AsyncRequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
where TRequest : notnull
{
async Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
{
await Handle(request, exception, state, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">The thrown exception</param>
/// <param name="state">The current state of handling the exception</param>
/// <param name="cancellationToken">Cancellation token</param>
protected abstract Task Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken);
}

/// <summary>
/// Wrapper class that synchronously handles an exception from request
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public abstract class RequestExceptionHandler<TRequest, TResponse, TException> : IRequestExceptionHandler<TRequest, TResponse, TException>
where TRequest : notnull
where TException : Exception
{
Task IRequestExceptionHandler<TRequest, TResponse, TException>.Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
{
Handle(request, exception, state);
return Task.CompletedTask;
}

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">The thrown exception</param>
/// <param name="state">The current state of handling the exception</param>
protected abstract void Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state);
}

/// <summary>
/// Wrapper class that synchronously handles a base exception from request
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public abstract class RequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
where TRequest : notnull
{
Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
{
Handle(request, exception, state);
return Task.CompletedTask;
}

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Failed request</param>
/// <param name="exception">The thrown exception</param>
/// <param name="state">The current state of handling the exception</param>
protected abstract void Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state);
}
3 changes: 1 addition & 2 deletions src/MediatR/Pipeline/RequestExceptionProcessorBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ namespace MediatR.Pipeline;
using System.Threading.Tasks;

/// <summary>
/// Behavior for executing all <see cref="IRequestExceptionHandler{TRequest,TResponse,TException}"/>
/// or <see cref="RequestExceptionHandler{TRequest,TResponse}"/> instances
/// Behavior for executing all <see cref="IRequestExceptionHandler{TRequest,TResponse,TException}"/> instances
/// after an exception is thrown by the following pipeline steps
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
Expand Down
4 changes: 2 additions & 2 deletions test/MediatR.Tests/MicrosoftExtensionsDI/PipelineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public Task Process(Ping request, Pong response, CancellationToken cancellationT
}
}

public class PingPongGenericExceptionAction : IRequestExceptionAction<Ping>
public class PingPongGenericExceptionAction : IRequestExceptionAction<Ping, Exception>
{
private readonly Logger _output;

Expand Down Expand Up @@ -301,7 +301,7 @@ public Task Handle(Ping request, ApplicationException exception, RequestExceptio
}
}

public class PingPongGenericExceptionHandler : IRequestExceptionHandler<Ping, Pong>
public class PingPongGenericExceptionHandler : IRequestExceptionHandler<Ping, Pong, Exception>
{
private readonly Logger _output;

Expand Down
4 changes: 2 additions & 2 deletions test/MediatR.Tests/Pipeline/RequestExceptionActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public Task<Pong> Handle(Ping request, CancellationToken cancellationToken)
}
}

public class GenericExceptionAction<TRequest> : IRequestExceptionAction<TRequest> where TRequest : notnull
public class GenericExceptionAction<TRequest> : IRequestExceptionAction<TRequest, Exception> where TRequest : notnull
{
public int ExecutionCount { get; private set; }

Expand Down Expand Up @@ -126,7 +126,7 @@ public async Task Should_run_matching_exception_actions_only_once()
var container = new Container(cfg =>
{
cfg.For<IRequestHandler<Ping, Pong>>().Use<PingHandler>();
cfg.For<IRequestExceptionAction<Ping>>().Use(_ => genericExceptionAction);
cfg.For<IRequestExceptionAction<Ping, Exception>>().Use(_ => genericExceptionAction);
cfg.For(typeof(IPipelineBehavior<,>)).Add(typeof(RequestExceptionActionProcessorBehavior<,>));
cfg.For<IMediator>().Use<Mediator>();
});
Expand Down
20 changes: 12 additions & 8 deletions test/MediatR.Tests/Pipeline/RequestExceptionHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Task<Pong> Handle(Ping request, CancellationToken cancellationToken)
}
}

public class GenericPingExceptionHandler : IRequestExceptionHandler<Ping, Pong>
public class GenericPingExceptionHandler : IRequestExceptionHandler<Ping, Pong, Exception>
{
public int ExecutionCount { get; private set; }

Expand All @@ -56,25 +56,29 @@ public Task Handle(Ping request, PingException exception, RequestExceptionHandle
}
}

public class PingPongExceptionHandler : RequestExceptionHandler<Ping, Pong>
public class PingPongExceptionHandler : IRequestExceptionHandler<Ping, Pong, Exception>
{
protected override void Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state)
public Task Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state, CancellationToken token)
{
state.SetHandled(new Pong() { Message = exception.Message + " Handled"});

return Task.CompletedTask;
}
}

public class PingPongExceptionHandlerNotHandled : RequestExceptionHandler<Ping, Pong>
public class PingPongExceptionHandlerNotHandled : IRequestExceptionHandler<Ping, Pong, Exception>
{
protected override void Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state)
public Task Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state, CancellationToken token)
{
request.Message = exception.Message + " Not Handled";

return Task.CompletedTask;
}
}

public class PingPongThrowingExceptionHandler : RequestExceptionHandler<Ping, Pong>
public class PingPongThrowingExceptionHandler : IRequestExceptionHandler<Ping, Pong, Exception>
{
protected override void Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state)
public Task Handle(Ping request, Exception exception, RequestExceptionHandlerState<Pong> state, CancellationToken token)
{
throw new ApplicationException("Surprise!");
}
Expand Down Expand Up @@ -148,7 +152,7 @@ public async Task Should_run_matching_exception_handlers_only_once()
var container = new Container(cfg =>
{
cfg.For<IRequestHandler<Ping, Pong>>().Use<PingHandler>();
cfg.For<IRequestExceptionHandler<Ping, Pong>>().Use(genericPingExceptionHandler);
cfg.For<IRequestExceptionHandler<Ping, Pong, Exception>>().Use(genericPingExceptionHandler);
cfg.For(typeof(IPipelineBehavior<,>)).Add(typeof(RequestExceptionProcessorBehavior<,>));
cfg.For<IMediator>().Use<Mediator>();
});
Expand Down