Skip to content

Commit

Permalink
Merge branch 'jbogard:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
jithu7432 authored Sep 22, 2024
2 parents 84b3621 + 0d3bf4c commit b554639
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 234 deletions.
20 changes: 20 additions & 0 deletions src/MediatR/Entities/OpenBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using Microsoft.Extensions.DependencyInjection;

namespace MediatR.Entities;
/// <summary>
/// Creates open behavior entity.
/// </summary>
public class OpenBehavior
{
public OpenBehavior(Type openBehaviorType, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
{
OpenBehaviorType = openBehaviorType;
ServiceLifetime = serviceLifetime;
}

public Type? OpenBehaviorType { get; }
public ServiceLifetime ServiceLifetime { get; }


}
2 changes: 1 addition & 1 deletion src/MediatR/IPipelineBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace MediatR;
/// </summary>
/// <typeparam name="TResponse">Response type</typeparam>
/// <returns>Awaitable task returning a <typeparamref name="TResponse"/></returns>
public delegate Task<TResponse> RequestHandlerDelegate<TResponse>();
public delegate Task<TResponse> RequestHandlerDelegate<TResponse>(CancellationToken t = default);

/// <summary>
/// Pipeline behavior to surround the inner handler.
Expand Down
34 changes: 33 additions & 1 deletion src/MediatR/MicrosoftExtensionsDI/MediatrServiceConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using MediatR;
using MediatR.Entities;
using MediatR.NotificationPublishers;
using MediatR.Pipeline;
using MediatR.Registration;
Expand Down Expand Up @@ -92,7 +93,7 @@ public class MediatRServiceConfiguration
/// <summary>
/// Flag that controlls whether MediatR will attempt to register handlers that containg generic type parameters.
/// </summary>
public bool RegisterGenericHandlers { get; set; } = true;
public bool RegisterGenericHandlers { get; set; } = false;

/// <summary>
/// Register various handlers from assembly containing given type
Expand Down Expand Up @@ -222,6 +223,37 @@ public MediatRServiceConfiguration AddOpenBehavior(Type openBehaviorType, Servic
return this;
}

/// <summary>
/// Registers multiple open behavior types against the <see cref="IPipelineBehavior{TRequest,TResponse}"/> open generic interface type
/// </summary>
/// <param name="openBehaviorTypes">An open generic behavior type list includes multiple open generic behavior types.</param>
/// <param name="serviceLifetime">Optional service lifetime, defaults to <see cref="ServiceLifetime.Transient"/>.</param>
/// <returns>This</returns>
public MediatRServiceConfiguration AddOpenBehaviors(IEnumerable<Type> openBehaviorTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
{
foreach (var openBehaviorType in openBehaviorTypes)
{
AddOpenBehavior(openBehaviorType, serviceLifetime);
}

return this;
}

/// <summary>
/// Registers open behaviors against the <see cref="IPipelineBehavior{TRequest,TResponse}"/> open generic interface type
/// </summary>
/// <param name="openBehaviors">An open generic behavior list includes multiple <see cref="OpenBehavior"/> open generic behaviors.</param>
/// <returns>This</returns>
public MediatRServiceConfiguration AddOpenBehaviors(IEnumerable<OpenBehavior> openBehaviors)
{
foreach (var openBehavior in openBehaviors)
{
AddOpenBehavior(openBehavior.OpenBehaviorType!, openBehavior.ServiceLifetime);
}

return this;
}

/// <summary>
/// Register a closed stream behavior type
/// </summary>
Expand Down
5 changes: 1 addition & 4 deletions src/MediatR/Registration/ServiceRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,7 @@ private static (Type Service, Type Implementation) GetConcreteRegistrationTypes(
var constraintsForEachParameter = openRequestHandlerImplementation
.GetGenericArguments()
.Select(x => x.GetGenericParameterConstraints())
.ToList();

if (constraintsForEachParameter.Count > 2 && constraintsForEachParameter.Any(constraints => !constraints.Where(x => x.IsInterface || x.IsClass).Any()))
throw new ArgumentException($"Error registering the generic handler type: {openRequestHandlerImplementation.FullName}. When registering generic requests with more than two type parameters, each type parameter must have at least one constraint of type interface or class.");
.ToList();

var typesThatCanCloseForEachParameter = constraintsForEachParameter
.Select(constraints => assembliesToScan
Expand Down
12 changes: 6 additions & 6 deletions src/MediatR/Wrappers/RequestHandlerWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ public class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrap
public override Task<TResponse> Handle(IRequest<TResponse> request, IServiceProvider serviceProvider,
CancellationToken cancellationToken)
{
Task<TResponse> Handler() => serviceProvider.GetRequiredService<IRequestHandler<TRequest, TResponse>>()
.Handle((TRequest) request, cancellationToken);
Task<TResponse> Handler(CancellationToken t = default) => serviceProvider.GetRequiredService<IRequestHandler<TRequest, TResponse>>()
.Handle((TRequest) request, t == default ? cancellationToken : t);

return serviceProvider
.GetServices<IPipelineBehavior<TRequest, TResponse>>()
.Reverse()
.Aggregate((RequestHandlerDelegate<TResponse>) Handler,
(next, pipeline) => () => pipeline.Handle((TRequest) request, next, cancellationToken))();
(next, pipeline) => (t) => pipeline.Handle((TRequest) request, next, t == default ? cancellationToken : t))();
}
}

Expand All @@ -55,10 +55,10 @@ public class RequestHandlerWrapperImpl<TRequest> : RequestHandlerWrapper
public override Task<Unit> Handle(IRequest request, IServiceProvider serviceProvider,
CancellationToken cancellationToken)
{
async Task<Unit> Handler()
async Task<Unit> Handler(CancellationToken t = default)
{
await serviceProvider.GetRequiredService<IRequestHandler<TRequest>>()
.Handle((TRequest) request, cancellationToken);
.Handle((TRequest) request, t == default ? cancellationToken : t);

return Unit.Value;
}
Expand All @@ -67,6 +67,6 @@ await serviceProvider.GetRequiredService<IRequestHandler<TRequest>>()
.GetServices<IPipelineBehavior<TRequest, Unit>>()
.Reverse()
.Aggregate((RequestHandlerDelegate<Unit>) Handler,
(next, pipeline) => () => pipeline.Handle((TRequest) request, next, cancellationToken))();
(next, pipeline) => (t) => pipeline.Handle((TRequest) request, next, t == default ? cancellationToken : t))();
}
}
23 changes: 5 additions & 18 deletions test/MediatR.Tests/GenericRequestHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void ShouldResolveAllCombinationsOfGenericHandler(int numberOfClasses, in
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblies(dynamicAssembly);
cfg.RegisterGenericHandlers = true;
});

var provider = services.BuildServiceProvider();
Expand Down Expand Up @@ -93,24 +94,6 @@ public void ShouldNotRegisterDuplicateHandlers(int numberOfClasses, int numberOf
hasDuplicates.ShouldBeFalse();
}

[Fact]
public void ShouldThrowExceptionWhenRegisterningHandlersWithNoConstraints()
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton(new Logger());

var assembly = GenerateMissingConstraintsAssembly();

Should.Throw<ArgumentException>(() =>
{
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(assembly);
});
})
.Message.ShouldContain("When registering generic requests with more than two type parameters, each type parameter must have at least one constraint of type interface or class.");
}

[Fact]
public void ShouldThrowExceptionWhenTypesClosingExceedsMaximum()
{
Expand All @@ -124,6 +107,7 @@ public void ShouldThrowExceptionWhenTypesClosingExceedsMaximum()
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(assembly);
cfg.RegisterGenericHandlers = true;
});
})
.Message.ShouldContain("One of the generic type parameter's count of types that can close exceeds the maximum length allowed");
Expand All @@ -142,6 +126,7 @@ public void ShouldThrowExceptionWhenGenericHandlerRegistrationsExceedsMaximum()
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(assembly);
cfg.RegisterGenericHandlers = true;
});
})
.Message.ShouldContain("The total number of generic type registrations exceeds the maximum allowed");
Expand All @@ -160,6 +145,7 @@ public void ShouldThrowExceptionWhenGenericTypeParametersExceedsMaximum()
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(assembly);
cfg.RegisterGenericHandlers = true;
});
})
.Message.ShouldContain("The number of generic type parameters exceeds the maximum allowed");
Expand All @@ -181,6 +167,7 @@ public void ShouldThrowExceptionWhenTimeoutOccurs()
cfg.MaxGenericTypeRegistrations = 0;
cfg.MaxTypesClosing = 0;
cfg.RegistrationTimeout = 1000;
cfg.RegisterGenericHandlers = true;
cfg.RegisterServicesFromAssembly(assembly);
});
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ public AssemblyResolutionTests()
{
IServiceCollection services = new ServiceCollection();
services.AddSingleton(new Logger());
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Ping).Assembly));
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Ping).Assembly);
cfg.RegisterGenericHandlers = true;
});
_provider = services.BuildServiceProvider();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
namespace MediatR.Tests.MicrosoftExtensionsDI
{
public abstract class BaseGenericRequestHandlerTests
{

protected static Assembly GenerateMissingConstraintsAssembly() =>
CreateAssemblyModuleBuilder("MissingConstraintsAssembly", 3, 3, CreateHandlerForMissingConstraintsTest);

{
protected static Assembly GenerateTypesClosingExceedsMaximumAssembly() =>
CreateAssemblyModuleBuilder("ExceedsMaximumTypesClosingAssembly", 201, 1, CreateHandlerForExceedsMaximumClassesTest);

Expand Down
Loading

0 comments on commit b554639

Please sign in to comment.