Skip to content

Commit

Permalink
Merge pull request #552 from SimonCropp/deferReflection
Browse files Browse the repository at this point in the history
Defer handler reflection
  • Loading branch information
jbogard committed Oct 7, 2020
2 parents 168a433 + 678773f commit 5368db6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 20 deletions.
27 changes: 15 additions & 12 deletions src/MediatR/Mediator.cs
Expand Up @@ -48,19 +48,22 @@ public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, Cancellation
throw new ArgumentNullException(nameof(request));
}
var requestType = request.GetType();
var requestInterfaceType = requestType
.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequest<>));
var isValidRequest = requestInterfaceType != null;

if (!isValidRequest)
{
throw new ArgumentException($"{nameof(request)} does not implement ${nameof(IRequest)}");
}

var responseType = requestInterfaceType!.GetGenericArguments()[0];
var handler = _requestHandlers.GetOrAdd(requestType,
t => (RequestHandlerBase)Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, responseType)));
requestTypeKey =>
{
var requestInterfaceType = requestTypeKey
.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequest<>));
var isValidRequest = requestInterfaceType != null;
if (!isValidRequest)
{
throw new ArgumentException($"{requestType.Name} does not implement {nameof(IRequest)}", nameof(request));
}
var responseType = requestInterfaceType!.GetGenericArguments()[0];
return (RequestHandlerBase)Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestTypeKey, responseType));
});

// call via dynamic dispatch to avoid calling through reflection for performance reasons
return handler.Handle(request, cancellationToken, _serviceFactory);
Expand Down
44 changes: 36 additions & 8 deletions test/MediatR.Tests/ExceptionTests.cs
Expand Up @@ -244,17 +244,17 @@ public async Task Should_throw_argument_exception_for_publish_when_request_is_no

public class PingException : IRequest
{

}

public class PingExceptionHandler : IRequestHandler<PingException>
{
public Task<Unit> Handle(PingException request, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}

[Fact]
public async Task Should_throw_exception_for_non_generic_send_when_exception_occurs()
{
Expand All @@ -271,12 +271,40 @@ public async Task Should_throw_exception_for_non_generic_send_when_exception_occ
cfg.For<IMediator>().Use<Mediator>();
});
var mediator = container.GetInstance<IMediator>();

object pingException = new PingException();

await Should.ThrowAsync<NotImplementedException>(async () => await mediator.Send(pingException));
}


[Fact]
public async Task Should_throw_exception_for_non_request_send()
{
var container = new Container(cfg =>
{
cfg.Scan(scanner =>
{
scanner.AssemblyContainingType(typeof(NullPinged));
scanner.IncludeNamespaceContainingType<Ping>();
scanner.WithDefaultConventions();
scanner.AddAllTypesOf(typeof(IRequestHandler<,>));
});
cfg.For<ServiceFactory>().Use<ServiceFactory>(ctx => t => ctx.GetInstance(t));
cfg.For<IMediator>().Use<Mediator>();
});
var mediator = container.GetInstance<IMediator>();

object nonRequest = new NonRequest();

var argumentException = await Should.ThrowAsync<ArgumentException>(async () => await mediator.Send(nonRequest));
Assert.StartsWith("NonRequest does not implement IRequest", argumentException.Message);
}

public class NonRequest
{

}

[Fact]
public async Task Should_throw_exception_for_generic_send_when_exception_occurs()
{
Expand All @@ -293,9 +321,9 @@ public async Task Should_throw_exception_for_generic_send_when_exception_occurs(
cfg.For<IMediator>().Use<Mediator>();
});
var mediator = container.GetInstance<IMediator>();

PingException pingException = new PingException();

await Should.ThrowAsync<NotImplementedException>(async () => await mediator.Send(pingException));
}
}
Expand Down

0 comments on commit 5368db6

Please sign in to comment.