Skip to content

Commit

Permalink
Merge pull request #921 from jbogard/consolidate-exception-interfaces
Browse files Browse the repository at this point in the history
Removing extraneous interfaces and classes for exceptions
  • Loading branch information
jbogard authored Jul 6, 2023
2 parents f08b0bc + 5197afe commit 4452ce8
Show file tree
Hide file tree
Showing 10 changed files with 23 additions and 176 deletions.
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

0 comments on commit 4452ce8

Please sign in to comment.