Home > Back-end >  Registering constrained MediatR pipeline behaviour in DI injection container
Registering constrained MediatR pipeline behaviour in DI injection container

Time:09-21

I have the following MediatR behavior:

public class FailFastRequestBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
    where TResponse : BaseResponse
{
    ...
}

and is registered in default ASP.NET Core DI container like this:

services.AddScoped(
    typeof(IPipelineBehavior<,>),
    typeof(FailFastRequestBehavior<,>));

which handles commands like this:

public class Command: IRequest<BaseResponse>
{
    ...
}

This works great, but the BaseResponse class has a property that can contain the command result, and this way it's typed as object, which is not great.

And I would like to make the BaseResponse Generic, so the commands would be something like:

public class Command: IRequest<BaseResponse<MyObject>>
{
    ...
}

How could I change the behavior signature to support this and then properly register it? If it's even possible...

I tried several things, but the one that seems more reasonable for me is this:

public class FailFastRequestBehavior<TRequest, TResponse, TValue>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
    where TResponse : BaseResponse<TValue>
{
    ...
}

But then my behavior has 3 generic parameters and the MediatR interface has only 2, and I cannot register it in the DI container.

Any suggestions?

CodePudding user response:

But then my behavior has 3 generic parameters and the MediatR interface has only 2, and I cannot register it in the DI container.

This is impossible to achieve with MS.DI. MS.DI has the restriction that it requires the implementation to have the exact generic type arguments in the exact order as the implemented interface.

This means that this works:

  • X : I
  • X<A, B> : I<A, B>
  • X<A, B, C> : I<A, B, C>

And this can't be resolved:

  • X : I<IFoo>
  • X<A, B> : I<B, A>
  • X<A, B, C> : I<B, A>

Some of the other DI Containers do have better support for these kinds of generic structures, but with MS.DI, each generic implementation must be constructable as follows:

Type typeDefinitionImplementation; // e.g. X<T1, T1>
Type closedGenericInterface; // e.g. IX<Foo, Bar>

// Arguments in the order of the interface definition.
// e.g. IX<Foo, Bar> results in { Foo, Bar }
Type[] typeArgs = closedGenericInterface.GetGenericArguments();

// close type must be constructable using the typeArgs array.
// e.g. X<T1, T1>   { Foo, Bar } = X<Foo, Bar>
Type closedImpl = typeDefinitionImplementation.MakeGenericType(typeArgs);
  • Related