Skip to content

Instantly share code, notes, and snippets.

@tombatron
Last active May 19, 2017 18:22
Show Gist options
  • Save tombatron/80b7ac3077655541606f0080802d8d90 to your computer and use it in GitHub Desktop.
Save tombatron/80b7ac3077655541606f0080802d8d90 to your computer and use it in GitHub Desktop.
Setup MediatR, with "decorator" support.
using Autofac;
using Autofac.Features.Variance;
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Mediatr.Extras.Autofac
{
public static class AutofacExtensions
{
private static readonly Type[] MediatRTypes = new[]
{
typeof(IRequestHandler<>),
typeof(IRequestHandler<,>),
typeof(IAsyncRequestHandler<>),
typeof(IAsyncRequestHandler<,>),
typeof(ICancellableAsyncRequestHandler<>),
typeof(ICancellableAsyncRequestHandler<,>),
typeof(INotificationHandler<>),
typeof(IAsyncNotificationHandler<>),
typeof(ICancellableAsyncNotificationHandler<>),
};
public static void RegisterMediatR(this ContainerBuilder @this, Assembly[] assemblies, Action<ContainerBuilder> preMediatRRegistration = null)
{
preMediatRRegistration?.Invoke(@this);
foreach (var assembly in assemblies)
{
RegisterMediatRHandlers(@this, assembly);
}
RegisterMediatRFactories(@this);
}
private static void RegisterMediatRFactories(ContainerBuilder builder)
{
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.Register<SingleInstanceFactory>(ctx =>
{
var c = ctx.Resolve<IComponentContext>();
return t =>
{
object o;
return c.TryResolve(t, out o) ? o : null;
};
});
builder.Register<MultiInstanceFactory>(ctx =>
{
var c = ctx.Resolve<IComponentContext>();
return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
});
}
private static void RegisterMediatRHandlers(ContainerBuilder builder, Assembly assembly)
{
var types = assembly.GetTypes()
.Where(t => t.GetInterfaces()
.Any(i => MediatRTypes
.Any(x => i.IsClosedTypeOf(x))));
builder.RegisterTypes(types.ToArray())
.PreserveExistingDefaults()
.AsImplementedInterfaces();
}
}
}
using Autofac;
using MediatR;
using MediatR.Extras.Autofac.TestAssembly;
using System.Reflection;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;
namespace Mediatr.Extras.Autofac.Tests
{
public class AutofacExtensionsTests
{
private static readonly Assembly TestAssembly = Assembly.Load("MediatR.Extras.Autofac.TestAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
public class ItCanRegister
{
public class IRequestHandlers
{
[Fact]
public void WithOneGenericTypeParameterCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new RequestWithNoResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
[Fact]
public void WithTwoGenericTypeParametersCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new RequestWithResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
}
public class IAsyncRequestHandlers
{
[Fact]
public void WithOneGenericTypeParameterCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new AsyncRequestWithNoResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
[Fact]
public void WithTwoGenericTypeParametersCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new AsyncRequestWithResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
}
public class ICancellableAsyncRequestHandlers
{
[Fact]
public void WithOneGenericTypeParameterCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new CancellableAsyncRequestWithNoResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
[Fact]
public void WithTwoGenericTypeParametersCorrectly()
{
using (var scope = GetAutofacScope())
{
var request = new CancellableAsyncRequestWithResult();
var mediatr = scope.Resolve<IMediator>();
mediatr.Send(request);
}
}
}
public class INotificationHandlers
{
[Fact]
public void Correctly()
{
using (var scope = GetAutofacScope())
{
var notification = new ExampleNotification();
var mediatr = scope.Resolve<IMediator>();
mediatr.Publish(notification);
}
}
}
public class IAsyncNotificationsHandlers
{
[Fact]
public void Correctly()
{
using (var scope = GetAutofacScope())
{
var notification = new ExampleAsyncNotification();
var mediatr = scope.Resolve<IMediator>();
mediatr.Publish(notification);
}
}
}
public class ICancellableAsyncNotificationHandlers
{
[Fact]
public void Correctly()
{
using (var scope = GetAutofacScope())
{
var notification = new ExampleCancellableAsyncNotification();
var mediatr = scope.Resolve<IMediator>();
mediatr.Publish(notification);
}
}
}
}
public class ItCanDecorate
{
private readonly ITestOutputHelper _output;
public ItCanDecorate(ITestOutputHelper output)
{
_output = output;
}
[Fact]
public async Task AHandler()
{
var builder = new ContainerBuilder();
builder.RegisterMediatR(new[] { TestAssembly }, (b) =>
{
b.RegisterType<RequestWithResultHandler>()
.Named<IRequestHandler<RequestWithResult, string>>("example");
b.RegisterDecorator<IRequestHandler<RequestWithResult, string>>(
(c, inner) => new TestDecorator1(inner),
fromKey: "example"
).Named<IRequestHandler<RequestWithResult, string>>("example_with_decorator_1");
b.RegisterDecorator<IRequestHandler<RequestWithResult, string>>(
(c, inner) => new TestDecorator2(inner),
fromKey: "example_with_decorator_1"
);
});
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var mediator = scope.Resolve<IMediator>();
var result = await mediator.Send(new RequestWithResult());
var result2 = await mediator.Send(new AsyncRequestWithResult());
_output.WriteLine(result);
_output.WriteLine(result2);
}
}
}
private static ILifetimeScope GetAutofacScope()
{
var builder = new ContainerBuilder();
builder.RegisterMediatR(new[] { TestAssembly });
var container = builder.Build();
return container.BeginLifetimeScope();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment