Skip to content

Instantly share code, notes, and snippets.

@anderly
Last active December 12, 2019 19:52
Show Gist options
  • Save anderly/576aece4c7c37ce8a6cc1fc5a7f6bb9e to your computer and use it in GitHub Desktop.
Save anderly/576aece4c7c37ce8a6cc1fc5a7f6bb9e to your computer and use it in GitHub Desktop.
MediatR Fallback Pipeline Behavior
public class Handler : IRequestHandler<Query, Customer>, IFallbackHandler<Query, Customer>
{
private readonly ICustomerRepository _db;
private readonly ICustomerRepository<SourceSystem.Secondary> _db2;
private readonly IConfigurationProvider _configuration;
public Handler(ICustomerRepository db, ICustomerRepository<SourceSystem.Secondary> db2, IConfigurationProvider configuration)
{
_db = db;
_db2 = db2;
_configuration = configuration;
}
public async Task<Customer> Handle(Query message, CancellationToken token)
{
return await _db.GetCustomerByNumberAsync(message.CustomerNumber);
}
// HandleFallback method from IFallbackHandler<TRequest, TResponse> interface.
// This method will get called if my Handle method fails.
public async Task<Customer> HandleFallback(Query message, CancellationToken token)
{
return await _db2.GetCustomerByNumberAsync(message.CustomerNumber);
}
}
/// <summary>
/// MediatR Fallback Pipeline Behavior
/// </summary>
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
public class FallbackBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IFallbackHandler<TRequest, TResponse>> _fallbackHandlers;
private readonly ILogger<FallbackBehavior<TRequest, TResponse>> _logger;
public FallbackBehavior(IEnumerable<IFallbackHandler<TRequest, TResponse>> fallbackHandlers, ILogger<FallbackBehavior<TRequest, TResponse>> logger)
{
_fallbackHandlers = fallbackHandlers;
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var fallbackHandler = _fallbackHandlers.FirstOrDefault();
if (fallbackHandler == null)
{
// No fallback handler found, continue through pipeline
return await next();
}
var fallbackPolicy = Policy<TResponse>
.Handle<Exception>()
.FallbackAsync(async (cancellationToken) =>
{
_logger.LogDebug($"Initial handler failed. Falling back to `{fallbackHandler.GetType().FullName}@HandleFallback`");
return await fallbackHandler.HandleFallback(request, cancellationToken)
.ConfigureAwait(false);
});
var response = await fallbackPolicy.ExecuteAsync(async () => await next());
return response;
}
}
public interface IFallbackHandler<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
Task<TResponse> HandleFallback(TRequest request, CancellationToken cancellationToken);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment