Skip to content

Commit

Permalink
Consolidating interfaces to just the one IRequestHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
jbogard committed Apr 4, 2018
1 parent db6df5b commit 494e061
Show file tree
Hide file tree
Showing 23 changed files with 220 additions and 275 deletions.
8 changes: 1 addition & 7 deletions samples/MediatR.Examples.AspNetCore/Program.cs
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MediatR.Pipeline;
Expand All @@ -20,7 +19,7 @@ private static IMediator BuildMediator(WrappingWriter writer)
{
var services = new ServiceCollection();

services.AddScoped<ServiceFactory>(p => p.GetRequiredService);
services.AddScoped<ServiceFactory>(p => p.GetService);

services.AddSingleton<TextWriter>(writer);

Expand All @@ -46,10 +45,5 @@ private static IMediator BuildMediator(WrappingWriter writer)

return provider.GetRequiredService<IMediator>();
}

private static IEnumerable<object> GetRequiredServices(this IServiceProvider provider, Type serviceType)
{
return (IEnumerable<object>) provider.GetRequiredService(typeof(IEnumerable<>).MakeGenericType(serviceType));
}
}
}
1 change: 0 additions & 1 deletion samples/MediatR.Examples.Autofac/Program.cs
Expand Up @@ -27,7 +27,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
var mediatrOpenTypes = new[]
{
typeof(IRequestHandler<,>),
typeof(IRequestHandler<>),
typeof(INotificationHandler<>),
};

Expand Down
280 changes: 140 additions & 140 deletions samples/MediatR.Examples.DryIocZero/Container.Generated.cs

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions samples/MediatR.Examples.DryIocZero/Registrations.ttinclude
Expand Up @@ -41,10 +41,8 @@ ServiceInfo[] SpecifyResolutionRoots(ServiceRegistrationInfo reg)
// Close known open-generics.
// NOTE: This only needed because multiple services are located! via `MultiInstanceFactory` instead of to be injected as collection
: type == typeof(IRequestHandler<,>) ? new []{
reg.ToServiceInfo<IRequestHandler<Ping, Pong>>()
}
: type == typeof(IRequestHandler<>) ? new [] {
reg.ToServiceInfo<IRequestHandler<Jing>>()
reg.ToServiceInfo<IRequestHandler<Ping, Pong>>(),
reg.ToServiceInfo<IRequestHandler<Jing, Unit>>()
}
: type == typeof(IPipelineBehavior<,>) ? new []{
reg.ToServiceInfo<IPipelineBehavior<Ping, Pong>>(),
Expand Down
1 change: 0 additions & 1 deletion samples/MediatR.Examples.Lamar/Program.cs
Expand Up @@ -26,7 +26,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
{
scanner.AssemblyContainingType<Ping>();
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<>));
scanner.ConnectImplementationsToTypesClosing(typeof(INotificationHandler<>));
});
Expand Down
1 change: 0 additions & 1 deletion samples/MediatR.Examples.LightInject/Program.cs
Expand Up @@ -27,7 +27,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
serviceType.IsConstructedGenericType &&
(
serviceType.GetGenericTypeDefinition() == typeof(IRequestHandler<,>) ||
serviceType.GetGenericTypeDefinition() == typeof(IRequestHandler<>) ||
serviceType.GetGenericTypeDefinition() == typeof(INotificationHandler<>)
));

Expand Down
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Ninject" Version="3.3.4" />
<PackageReference Include="ninject.extensions.conventions" Version="3.3.0" />
</ItemGroup>

Expand Down
1 change: 0 additions & 1 deletion samples/MediatR.Examples.Ninject/Program.cs
Expand Up @@ -29,7 +29,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
kernel.Bind<TextWriter>().ToConstant(writer);

kernel.Bind(scan => scan.FromAssemblyContaining<Ping>().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<,>)).BindAllInterfaces());
kernel.Bind(scan => scan.FromAssemblyContaining<Ping>().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<>)).BindAllInterfaces());
kernel.Bind(scan => scan.FromAssemblyContaining<Ping>().SelectAllClasses().InheritedFrom(typeof(INotificationHandler<>)).BindAllInterfaces());

//Pipeline
Expand Down
1 change: 0 additions & 1 deletion samples/MediatR.Examples.SimpleInjector/Program.cs
Expand Up @@ -26,7 +26,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
var assemblies = GetAssemblies().ToArray();
container.RegisterSingleton<IMediator, Mediator>();
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Register(typeof(IRequestHandler<>), assemblies);

// we have to do this because by default, generic type definitions (such as the Constrained Notification Handler) won't be registered
var notificationHandlerTypes = container.GetTypesToRegister(typeof(INotificationHandler<>), assemblies, new TypesToRegisterOptions
Expand Down
1 change: 0 additions & 1 deletion samples/MediatR.Examples.StructureMap/Program.cs
Expand Up @@ -26,7 +26,6 @@ private static IMediator BuildMediator(WrappingWriter writer)
{
scanner.AssemblyContainingType<Ping>();
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<,>));
scanner.ConnectImplementationsToTypesClosing(typeof(IRequestHandler<>));
scanner.ConnectImplementationsToTypesClosing(typeof(INotificationHandler<>));
});
Expand Down
19 changes: 16 additions & 3 deletions samples/MediatR.Examples.Unity/Program.cs
Expand Up @@ -18,6 +18,8 @@ private static Task Main(string[] args)
var writer = new WrappingWriter(Console.Out);
var mediator = BuildMediator(writer);

writer.WriteLine("Unity is not a very good container and breaks immediately");

return Runner.Run(mediator, writer, "Unity");
}

Expand Down Expand Up @@ -49,13 +51,24 @@ public static class IUnityContainerExtensions
public static IUnityContainer RegisterMediator(this IUnityContainer container, LifetimeManager lifetimeManager)
{
return container.RegisterType<IMediator, Mediator>(lifetimeManager)
.RegisterInstance<ServiceFactory>(t => container.IsRegistered(t) ? container.Resolve(t) : null);
.RegisterInstance<ServiceFactory>(type =>
{
var enumerableType = type
.GetInterfaces()
.Concat(new[] { type })
.FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
return enumerableType != null
? container.ResolveAll(enumerableType.GetGenericArguments()[0])
: container.IsRegistered(type)
? container.Resolve(type)
: null;
});
}

public static IUnityContainer RegisterMediatorHandlers(this IUnityContainer container, Assembly assembly)
{
return container.RegisterTypesImplementingType(assembly, typeof(IRequestHandler<>))
.RegisterTypesImplementingType(assembly, typeof(IRequestHandler<,>))
return container.RegisterTypesImplementingType(assembly, typeof(IRequestHandler<,>))
.RegisterNamedTypesImplementingType(assembly, typeof(INotificationHandler<>));
}

Expand Down
12 changes: 10 additions & 2 deletions samples/MediatR.Examples.Windsor/Program.cs
@@ -1,3 +1,4 @@
using System.Linq;
using System.Threading.Tasks;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using MediatR.Pipeline;
Expand Down Expand Up @@ -27,12 +28,19 @@ private static IMediator BuildMediator(WrappingWriter writer)
container.Kernel.AddHandlersFilter(new ContravariantFilter());

container.Register(Classes.FromAssemblyContaining<Ping>().BasedOn(typeof(IRequestHandler<,>)).WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().BasedOn(typeof(IRequestHandler<>)).WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().BasedOn(typeof(INotificationHandler<>)).WithServiceAllInterfaces());

container.Register(Component.For<IMediator>().ImplementedBy<Mediator>());
container.Register(Component.For<TextWriter>().Instance(writer));
container.Register(Component.For<ServiceFactory>().UsingFactoryMethod<ServiceFactory>(k => k.Resolve));
container.Register(Component.For<ServiceFactory>().UsingFactoryMethod<ServiceFactory>(k => (type =>
{
var enumerableType = type
.GetInterfaces()
.Concat(new [] {type})
.FirstOrDefault(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
return enumerableType != null ? k.ResolveAll(enumerableType.GetGenericArguments()[0]) : k.Resolve(type);
})));

//Pipeline
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestPreProcessorBehavior<,>)).NamedAutomatically("PreProcessorBehavior"));
Expand Down
4 changes: 2 additions & 2 deletions samples/MediatR.Examples/JingHandler.cs
Expand Up @@ -4,7 +4,7 @@

namespace MediatR.Examples
{
public class JingHandler : IRequestHandler<Jing>
public class JingHandler : AsyncRequestHandler<Jing>
{
private readonly TextWriter _writer;

Expand All @@ -13,7 +13,7 @@ public JingHandler(TextWriter writer)
_writer = writer;
}

public Task Handle(Jing request, CancellationToken cancellationToken)
protected override Task Handle(Jing request)
{
return _writer.WriteLineAsync($"--- Handled Jing: {request.Message}, no Jong");
}
Expand Down
13 changes: 11 additions & 2 deletions samples/MediatR.Examples/Runner.cs
Expand Up @@ -23,7 +23,16 @@ public static async Task Run(IMediator mediator, WrappingWriter writer, string p
await mediator.Publish(new Pinged());

await writer.WriteLineAsync("Publishing Ponged...");
await mediator.Publish(new Ponged());
var failedPong = false;
try
{
await mediator.Publish(new Ponged());
}
catch (Exception e)
{
failedPong = true;
await writer.WriteLineAsync(e.ToString());
}

bool failedJing = false;
await writer.WriteLineAsync("Sending Jing...");
Expand Down Expand Up @@ -59,7 +68,7 @@ public static async Task Run(IMediator mediator, WrappingWriter writer, string p
OrderedPipelineBehaviors = order.SequenceEqual(order.OrderBy(i => i)),
NotificationHandler = contents.Contains("Got pinged async"),
MultipleNotificationHandlers = contents.Contains("Got pinged async") && contents.Contains("Got pinged also async"),
ConstrainedGenericNotificationHandler = contents.Contains("Got pinged constrained async"),
ConstrainedGenericNotificationHandler = contents.Contains("Got pinged constrained async") && !failedPong,
CovariantNotificationHandler = contents.Contains("Got notified")
};

Expand Down
12 changes: 2 additions & 10 deletions src/MediatR/IMediator.cs
Expand Up @@ -15,23 +15,15 @@ public interface IMediator
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation. The task result contains the handler response</returns>
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken));

/// <summary>
/// Asynchronously send a request to a single handler without expecting a response
/// </summary>
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation.</returns>
Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken));
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);

/// <summary>
/// Asynchronously send a notification to multiple handlers
/// </summary>
/// <param name="notification">Notification object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the publish operation.</returns>
Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default(CancellationToken))
Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default)
where TNotification : INotification;
}
}
2 changes: 1 addition & 1 deletion src/MediatR/IRequest.cs
Expand Up @@ -12,7 +12,7 @@ public interface IRequest : IRequest<Unit> { }
public interface IRequest<out TResponse> : IBaseRequest { }

/// <summary>
/// Allows for generic type constraints of objects implementing IRequest or IRequest<TResponse>
/// Allows for generic type constraints of objects implementing IRequest or IRequest{TResponse}
/// </summary>
public interface IBaseRequest { }
}
46 changes: 17 additions & 29 deletions src/MediatR/IRequestHandler.cs
Expand Up @@ -28,33 +28,36 @@ public interface IRequestHandler<in TRequest, TResponse>
public abstract class AsyncRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken)
=> HandleCore(request);
Task<TResponse> IRequestHandler<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken)
=> Handle(request);

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Request</param>
/// <returns>Response</returns>
protected abstract Task<TResponse> HandleCore(TRequest request);
protected abstract Task<TResponse> Handle(TRequest request);
}

/// <summary>
/// Wrapper class for a handler that asynchronously handles a request and does not return a response, ignoring the cancellation token
/// </summary>
/// <typeparam name="TRequest">The type of request being handled</typeparam>
public abstract class AsyncRequestHandler<TRequest> : IRequestHandler<TRequest>
public abstract class AsyncRequestHandler<TRequest> : IRequestHandler<TRequest, Unit>
where TRequest : IRequest
{
public Task Handle(TRequest request, CancellationToken cancellationToken)
=> HandleCore(request);
async Task<Unit> IRequestHandler<TRequest, Unit>.Handle(TRequest request, CancellationToken cancellationToken)
{
await Handle(request).ConfigureAwait(false);
return Unit.Value;
}

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Request</param>
/// <returns>Response</returns>
protected abstract Task HandleCore(TRequest request);
protected abstract Task Handle(TRequest request);
}

/// <summary>
Expand All @@ -65,45 +68,30 @@ public Task Handle(TRequest request, CancellationToken cancellationToken)
public abstract class RequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken)
=> Task.FromResult(HandleCore(request));
Task<TResponse> IRequestHandler<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken)
=> Task.FromResult(Handle(request));

/// <summary>
/// Override in a derived class for the handler logic
/// </summary>
/// <param name="request">Request</param>
/// <returns>Response</returns>
protected abstract TResponse HandleCore(TRequest request);
protected abstract TResponse Handle(TRequest request);
}

/// <summary>
/// Wrapper class for a handler that synchronously handles a request does not return a response
/// </summary>
/// <typeparam name="TRequest">The type of request being handled</typeparam>
public abstract class RequestHandler<TRequest> : IRequestHandler<TRequest>
public abstract class RequestHandler<TRequest> : IRequestHandler<TRequest, Unit>
where TRequest : IRequest
{
public Task Handle(TRequest request, CancellationToken cancellationToken)
Task<Unit> IRequestHandler<TRequest, Unit>.Handle(TRequest request, CancellationToken cancellationToken)
{
HandleCore(request);
Handle(request);
return Unit.Task;
}

protected abstract void HandleCore(TRequest request);
}

/// <summary>
/// Defines a handler for a request without a return value
/// </summary>
/// <typeparam name="TRequest">The type of request being handled</typeparam>
public interface IRequestHandler<in TRequest>
where TRequest : IRequest
{
/// <summary>
/// Handles a request
/// </summary>
/// <param name="request">The request</param>
/// <param name="cancellationToken">Cancellation token</param>
Task Handle(TRequest request, CancellationToken cancellationToken);
protected abstract void Handle(TRequest request);
}
}
27 changes: 0 additions & 27 deletions src/MediatR/Internal/RequestHandlerWrapper.cs
@@ -1,5 +1,3 @@
using System.Collections.Generic;

namespace MediatR.Internal
{
using System;
Expand Down Expand Up @@ -31,12 +29,6 @@ protected static THandler GetHandler<THandler>(ServiceFactory factory)
}
}

internal abstract class RequestHandlerWrapper : RequestHandlerBase
{
public abstract Task Handle(IRequest request, CancellationToken cancellationToken,
ServiceFactory serviceFactory);
}

internal abstract class RequestHandlerWrapper<TResponse> : RequestHandlerBase
{
public abstract Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken,
Expand All @@ -57,23 +49,4 @@ internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWr
.Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline.Handle((TRequest)request, cancellationToken, next))();
}
}

internal class RequestHandlerWrapperImpl<TRequest> : RequestHandlerWrapper
where TRequest : IRequest
{
public override Task Handle(IRequest request, CancellationToken cancellationToken,
ServiceFactory serviceFactory)
{
async Task<Unit> Handler()
{
await GetHandler<IRequestHandler<TRequest>>(serviceFactory).Handle((TRequest) request, cancellationToken).ConfigureAwait(false);
return Unit.Value;
}

return serviceFactory
.GetInstances<IPipelineBehavior<TRequest, Unit>>()
.Reverse()
.Aggregate((RequestHandlerDelegate<Unit>) Handler, (next, pipeline) => () => pipeline.Handle((TRequest)request, cancellationToken, next))();
}
}
}

0 comments on commit 494e061

Please sign in to comment.