Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions samples/MediatR.Examples.Windsor/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ private static Task Main(string[] args)
var writer = new WrappingWriter(Console.Out);
var mediator = BuildMediator(writer);

return Runner.Run(mediator, writer, "Castle.Windsor");
return Runner.Run(mediator, writer, "Castle.Windsor", true);
}

private static IMediator BuildMediator(WrappingWriter writer)
Expand All @@ -29,33 +29,83 @@ private static IMediator BuildMediator(WrappingWriter writer)

// *** The default lifestyle for Windsor is Singleton
// *** If you are using ASP.net, it's better to register your services with 'Per Web Request LifeStyle'.

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

var fromAssemblyContainingPing = Classes.FromAssemblyContaining<Ping>();
container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
container.Register(fromAssemblyContainingPing.BasedOn(typeof(INotificationHandler<>)).WithServiceAllInterfaces().AllowMultipleMatches());
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionActionProcessorBehavior<,>)));
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestExceptionProcessorBehavior<,>)));
container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestExceptionHandler<,,>)).WithServiceAllInterfaces().AllowMultipleMatches());
container.Register(fromAssemblyContainingPing.BasedOn(typeof(IStreamRequestHandler<,>)).WithServiceAllInterfaces().AllowMultipleMatches());
container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPreProcessor<>)).WithServiceAllInterfaces().AllowMultipleMatches());
container.Register(fromAssemblyContainingPing.BasedOn(typeof(IRequestPostProcessor<,>)).WithServiceAllInterfaces().AllowMultipleMatches());

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

var service = enumerableType?.GetGenericArguments()?[0];
var resolvedType = enumerableType != null ? k.ResolveAll(service) : k.Resolve(type);
var genericArguments = service?.GetGenericArguments();

// Handle exceptions even using the base request types
if (service == null
|| genericArguments == null
|| !service.IsInterface
|| !service.IsGenericType
|| !service.IsConstructedGenericType
|| !(service.GetGenericTypeDefinition()
?.IsAssignableTo(typeof(IRequestExceptionHandler<,,>)) ?? false)
|| genericArguments.Length != 3
|| !(genericArguments[0].BaseType?.IsClass ?? false))
{
return resolvedType;
}

var serviceFactory = k.Resolve<ServiceFactory>();
var baseRequestType = genericArguments[0].BaseType;
var response = genericArguments[1];
var exceptionType = genericArguments[2];

// Check if the base request type is valid
if (!baseRequestType.IsClass
|| baseRequestType == typeof(object)
|| ((!baseRequestType.GetInterfaces()
?.Any(i => i.IsAssignableFrom(typeof(IRequest<>)))) ?? true))
{
return resolvedType;
}

return enumerableType != null ? k.ResolveAll(enumerableType.GetGenericArguments()[0]) : k.Resolve(type);
var exceptionHandlerInterfaceType = typeof(IRequestExceptionHandler<,,>).MakeGenericType(baseRequestType, response, exceptionType);
var enumerableExceptionHandlerInterfaceType = typeof(IEnumerable<>).MakeGenericType(exceptionHandlerInterfaceType);

// This is assumed Array because this method calls ResolveAll when a IEnumerable<> is passed as argument
var firstArray = serviceFactory.Invoke(enumerableExceptionHandlerInterfaceType) as Array;
var secondArray = resolvedType is Array ? resolvedType as Array : new[] { resolvedType };
var resultArray = Array.CreateInstance(typeof(object), firstArray.Length + secondArray.Length);
Array.Copy(firstArray, resultArray, firstArray.Length);
Array.Copy(secondArray, 0, resultArray, firstArray.Length, secondArray.Length);

return resultArray;
})));

//Pipeline
container.Register(Component.For(typeof(IStreamPipelineBehavior<,>)).ImplementedBy(typeof(GenericStreamPipelineBehavior<,>)));
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestPreProcessorBehavior<,>)).NamedAutomatically("PreProcessorBehavior"));
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(RequestPostProcessorBehavior<,>)).NamedAutomatically("PostProcessorBehavior"));
container.Register(Component.For(typeof(IPipelineBehavior<,>)).ImplementedBy(typeof(GenericPipelineBehavior<,>)).NamedAutomatically("Pipeline"));
container.Register(Component.For(typeof(IRequestPreProcessor<>)).ImplementedBy(typeof(GenericRequestPreProcessor<>)).NamedAutomatically("PreProcessor"));
container.Register(Component.For(typeof(IRequestPostProcessor <,>)).ImplementedBy(typeof(GenericRequestPostProcessor<,>)).NamedAutomatically("PostProcessor"));
container.Register(Component.For(typeof(IRequestPostProcessor<,>)).ImplementedBy(typeof(GenericRequestPostProcessor<,>)).NamedAutomatically("PostProcessor"));
container.Register(Component.For(typeof(IRequestPostProcessor<,>), typeof(ConstrainedRequestPostProcessor<,>)).NamedAutomatically("ConstrainedRequestPostProcessor"));
container.Register(Component.For(typeof(INotificationHandler<>), typeof(ConstrainedPingedHandler<>)).NamedAutomatically("ConstrainedPingedHandler"));

var mediator = container.Resolve<IMediator>();

return mediator;
}
}
}
22 changes: 21 additions & 1 deletion samples/MediatR.Examples/ExceptionHandler/ExceptionsHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ protected override async Task Handle(PingResource request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(CommonExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
Expand All @@ -33,7 +38,12 @@ public async Task Handle(PingResource request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(ConnectionExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
Expand All @@ -49,7 +59,12 @@ public async Task Handle(PingResource request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(AccessDeniedExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
Expand All @@ -65,7 +80,12 @@ public virtual async Task Handle(PingNewResource request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(ServerExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ protected override async Task Handle(PingResourceTimeout request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(CommonExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
Expand All @@ -33,7 +38,12 @@ public override async Task Handle(PingNewResource request,
RequestExceptionHandlerState<Pong> state,
CancellationToken cancellationToken)
{
// Exception type name required because it is checked later in messages
await _writer.WriteLineAsync($"Handling {exception.GetType().FullName}");

// Exception handler type name required because it is checked later in messages
await _writer.WriteLineAsync($"---- Exception Handler: '{typeof(ServerExceptionHandler).FullName}'").ConfigureAwait(false);

state.SetHandled(new Pong());
}
}
}
4 changes: 3 additions & 1 deletion samples/MediatR.Examples/Runner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,9 @@ private static bool IsExceptionHandledBy<TException, THandler>(WrappingWriter wr
{
var messages = writer.Contents.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None).ToList();

// Note: For this handler type to be found in messages, it must be written in all tested exception handlers
return messages[messages.Count - 2].Contains(typeof(THandler).FullName)
// Note: For this exception type to be found in messages, exception must be written in all tested exception handlers
&& messages[messages.Count - 3].Contains(typeof(TException).FullName);
}
}
Expand Down Expand Up @@ -336,4 +338,4 @@ public override Task WriteLineAsync(string value)
public override Encoding Encoding => _innerWriter.Encoding;

public string Contents => _stringWriter.ToString();
}
}