Skip to content

Instantly share code, notes, and snippets.

@djeikyb
Last active September 15, 2021 11:18
Show Gist options
  • Save djeikyb/3ff042814fa0ad5ca2b7cbb16e0b5c77 to your computer and use it in GitHub Desktop.
Save djeikyb/3ff042814fa0ad5ca2b7cbb16e0b5c77 to your computer and use it in GitHub Desktop.
Example in-memory message pipeline with dotnet 5 and mediatr; includes request logging and root level exception handler Raw
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using MediatR.Pipeline;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace com.example
{
class Program
{
static void Main(string[] args)
{
Host.CreateDefaultBuilder(args)
.ConfigureLogging((_, logging) => logging
.AddSimpleConsole(builder =>
{
// builder.ColorBehavior = LoggerColorBehavior.Disabled;
builder.SingleLine = true;
})
)
.ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.UseStartup<Startup>())
.Build()
.Run();
}
}
class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR(typeof(Startup));
services.AddHostedService<Worker>();
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestExceptionProcessorBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestLogger<,>));
}
public void Configure(IApplicationBuilder app)
{
}
}
class Worker : BackgroundService
{
private readonly IMediator _mediator;
public Worker(IMediator mediator)
{
_mediator = mediator;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var minimumDelay = Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
await _mediator.Send(new Message {Text = "world",}, stoppingToken);
await minimumDelay;
}
}
}
class ExceptionLogger<TRequest, TResponse, TException>
: IRequestExceptionHandler<TRequest, TResponse, TException>
where TException : Exception
{
private readonly ILogger<ExceptionLogger<TRequest, TResponse, TException>> _logger;
public ExceptionLogger(ILogger<ExceptionLogger<TRequest, TResponse, TException>> logger)
{
_logger = logger;
}
public Task Handle(
TRequest request,
TException exception,
RequestExceptionHandlerState<TResponse> state,
CancellationToken cancellationToken
)
{
_logger.LogError(exception, "oh noes it borked");
state.SetHandled(default);
return Task.CompletedTask;
}
}
class RequestLogger<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<RequestLogger<TRequest, TResponse>> _logger;
public RequestLogger(ILogger<RequestLogger<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(
TRequest request,
CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next
)
{
TResponse rs;
try
{
rs = await next();
}
finally
{
_logger.LogInformation($"🐙🐙🐙 {typeof(TRequest)}");
}
return rs;
}
}
class Message : IRequest
{
public string Text { get; init; }
}
class Hello : AsyncRequestHandler<Message>
{
private readonly ILogger<Hello> _logger;
public Hello(ILogger<Hello> logger)
{
_logger = logger;
}
protected override Task Handle(Message request, CancellationToken cancellationToken)
{
throw new Exception("oops");
_logger.LogInformation(request.Text);
return Task.CompletedTask;
}
}
}
@djeikyb
Copy link
Author

djeikyb commented May 24, 2021

csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MediatR" Version="9.0.0"/>
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="9.0.0"/>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0"/>
  </ItemGroup>

</Project>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment