C# 仅针对特定接口类型(命令)执行MediatR预处理器

C# 仅针对特定接口类型(命令)执行MediatR预处理器,c#,generics,autofac,cqrs,mediatr,C#,Generics,Autofac,Cqrs,Mediatr,[注意:这是一个“替换”问题。第一个问题基于我的主要项目的代码,因此我用一个单一用途项目的代码重新回答了这个问题,该项目更清晰地说明了原则。问题仍然是一样的,只是表达得更好而已。] 情景 我正在尝试使用MediatR管道行为和Autofac为请求路由在CQRS请求管道上设置命令预处理器。我的目标是使预处理器仅为命令(ICommand)而不是所有请求(IRequest)运行,这将导致预处理器执行命令、查询和事件 问题 我可以让GenericPreProcessor或任何其他预处理器对所有类型的请求

[注意:这是一个“替换”问题。第一个问题基于我的主要项目的代码,因此我用一个单一用途项目的代码重新回答了这个问题,该项目更清晰地说明了原则。问题仍然是一样的,只是表达得更好而已。]

情景 我正在尝试使用MediatR管道行为和Autofac为请求路由在CQRS请求管道上设置命令预处理器。我的目标是使预处理器仅为命令(ICommand)而不是所有请求(IRequest)运行,这将导致预处理器执行命令、查询和事件

问题 我可以让GenericPreProcessor或任何其他预处理器对所有类型的请求都能正常运行,但我尝试“过滤”注入的任何方法要么返回错误,要么根本不执行所需的预处理器

我在Autofac中处理所有请求的管道配置如下所示:

// Pipeline pre/post processors
builder
    .RegisterGeneric(typeof(RequestPostProcessorBehavior<,>))
    .As(typeof(IPipelineBehavior<,>));

builder
    .RegisterGeneric(typeof(RequestPreProcessorBehavior<,>))
    .As(typeof(IPipelineBehavior<,>));

// Works as desired: Fires generic pre-processor for ALL requests, both cmd and query
builder
    .RegisterGeneric(typeof(GenericRequestPreProcessor<>))
    .As(typeof(IRequestPreProcessor<>));

// Works for all requests, but I need a way to limit it to commands
builder
    .RegisterGeneric(typeof(MyCommandPreProcessor<>))
    .As(typeof(IRequestPreProcessor<>));
//管道前/后处理器
建设者
.RegisterGeneric(类型(请求后处理器或行为))
.As(类型(IPipelineBehavior));
建设者
.RegisterGeneric(类型(请求预处理或行为))
.As(类型(IPipelineBehavior));
//按需工作:为所有请求(cmd和query)启动通用预处理器
建设者
.RegisterGeneric(类型(通用请求预处理器))
.As(类型(IRequestProcessor));
//适用于所有请求,但我需要一种方法将其限制为命令
建设者
.RegisterGeneric(类型(MyCommand和预处理器))
.As(类型(IRequestProcessor));
从概念上讲,我正在尝试做以下任何一项,但都失败了:

builder
    .RegisterGeneric(typeof(MyCommandPreProcessor<>)) // Note generic
    .As(typeof(IRequestPreProcessor<ICommand<>>));
    // Intellisense error "Unexpected use of an unbound generic"

builder
    .RegisterType(typeof(MyCommandPreProcessor)) // Note non-generic
    .As(typeof(IRequestPreProcessor<ICommand<>>)); 
    // Intellisense error "Unexpected use of an unbound generic"

builder
    .RegisterType(typeof(MyCommandPreProcessor)) // Note non-generic
    .As(typeof(IRequestPreProcessor<ICommand<CommonResult>>)); 
    // No errors, but MyCommandPreProcessor not firing
builder
.RegisterGeneric(typeof(MyCommandPreProcessor))//注释generic
.As(类型(IRequestProcessor));
//Intellisense错误“意外使用未绑定泛型”
建设者
.RegisterType(typeof(myCommand预处理器))//注意非泛型
.As(类型(IRequestProcessor));
//Intellisense错误“意外使用未绑定泛型”
建设者
.RegisterType(typeof(myCommand预处理器))//注意非泛型
.As(类型(IRequestProcessor));
//没有错误,但MyCommand预处理器未启动
我正在尝试MyCommand预处理器的两种不同配置,一种是通用配置,另一种是非通用配置,但我遇到了以下两种情况之一:

public class MyCommandPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
{
    public Task Process(TRequest request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
        return Task.CompletedTask;
    }
}

- OR -

public class MyCommandPreProcessor : IRequestPreProcessor<IRequest<ICommonResponse>>
{
    public Task Process(TRequest request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
        return Task.CompletedTask;
    }
}
公共类MyCommand预处理器:IRequestPreProcessor
{
公共任务流程(TRequest请求、CancellationToken CancellationToken)
{
WriteLine(“******MYCOMMAND”和名为******”的预处理器);
返回Task.CompletedTask;
}
}
-或-
公共类MyCommand预处理器:IRequestPreProcessor
{
公共任务流程(TRequest请求、CancellationToken CancellationToken)
{
WriteLine(“******MYCOMMAND”和名为******”的预处理器);
返回Task.CompletedTask;
}
}
我的问题

对于IRequest类型是ICommand的封闭类型,我可以注册一个仅限于fire的预处理器吗

辅助材料 GitHub上的项目

可以在以下位置查看或克隆整个最小示例项目:

Autofac MediatR配置

一个工作配置,所有请求都有一个GenericRequestPreProcessor

        builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();

        var mediatrOpenTypes = new[]
        {
            typeof(IRequestHandler<,>),
            typeof(IRequestHandler<>),
            typeof(INotificationHandler<>)
        };

        foreach (var mediatrOpenType in mediatrOpenTypes)
        {
            // Register all command handler in the same assembly as WriteLogMessageCommandHandler
            builder
                .RegisterAssemblyTypes(typeof(MyCommandHandler).GetTypeInfo().Assembly)
                .AsClosedTypesOf(mediatrOpenType)
                .AsImplementedInterfaces();

            // Register all QueryHandlers in the same assembly as GetExternalLoginQueryHandler
            builder
                .RegisterAssemblyTypes(typeof(MyQueryHandler).GetTypeInfo().Assembly)
                .AsClosedTypesOf(mediatrOpenType)
                .AsImplementedInterfaces();
        }

        // Pipeline pre/post processors
        builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
        builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
        builder.RegisterGeneric(typeof(GenericRequestPreProcessor<>)).As(typeof(IRequestPreProcessor<>));
        // builder.RegisterGeneric(typeof(GenericRequestPostProcessor<,>)).As(typeof(IRequestPostProcessor<,>));
        // builder.RegisterGeneric(typeof(GenericPipelineBehavior<,>)).As(typeof(IPipelineBehavior<,>));

        builder.Register<SingleInstanceFactory>(ctx =>
        {
            var c = ctx.Resolve<IComponentContext>();
            return t => c.Resolve(t);
        });

        builder.Register<MultiInstanceFactory>(ctx =>
        {
            var c = ctx.Resolve<IComponentContext>();
            return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
        });
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly.AsImplementedInterfaces();
var mediatrOpenTypes=new[]
{
类型(IRequestHandler),
类型(IRequestHandler),
类型(INotificationHandler)
};
foreach(mediatrOpenTypes中的var mediatrOpenType)
{
//在与WriteLogMessageCommandHandler相同的程序集中注册所有命令处理程序
建设者
.RegisterAssemblyTypes(typeof(myCommand Handler).GetTypeInfo().Assembly)
.AsClosedTypesOf(MediaTropentType)
.a实现接口();
//在与GetExternalLoginQueryHandler相同的程序集中注册所有QueryHandler
建设者
.RegisterAssemblyTypes(typeof(MyQueryHandler).GetTypeInfo().Assembly)
.AsClosedTypesOf(MediaTropentType)
.a实现接口();
}
//管道前/后处理器
RegisterGeneric(typeof(RequestPostProcessorBehavior)).As(typeof(IPipelineBehavior));
builder.RegisterGeneric(typeof(RequestPreProcessorBehavior)).As(typeof(IPipelineBehavior));
builder.RegisterGeneric(typeof(GenericRequestPreProcessor)).As(typeof(IRequestPreProcessor));
//builder.RegisterGeneric(typeof(GenericRequestPostProcessor)).As(typeof(IRequestPostProcessor));
//builder.RegisterGeneric(typeof(GenericPipelineBehavior)).As(typeof(IPipelineBehavior));
builder.Register(ctx=>
{
var c=ctx.Resolve();
返回t=>c.Resolve(t);
});
builder.Register(ctx=>
{
var c=ctx.Resolve();
返回t=>(IEnumerable)c.Resolve(typeof(IEnumerable).MakeGenericType(t));
});
myCommand预处理器类

// Requests

IMediatR.IRequest<TResponse>
    <- IMessage<TResponse>
        <- ICommand<TResponse>
            <- concrete MyCommand : ICommand<CommonResponse>
        <- IQuery<TResponse>
            <- concrete MyQuery : IQuery<CommonResponse>

// Request Handlers

IMediatR.IRequestHandler<in TRequest,TResponse>
    <- IMessageHandler<in TRequest,TResponse>
        <- ICommandHandler<in TRequest,TResponse> 
            <- concrete MyCommandHandler : ICommandHandler<MyCommand,CommonResponse>
        <- IQueryHandler<In TRequest,TResponse>
            <- concrete MyQueryHandler : IQueryHandler<MyQuery,CommonResponse>

// CommonResponse - A POCO that returns result info

ICommonResponse
    <- concrete CommonResponse
public interface IMessage<TResponse> : MediatR.IRequest<TResponse>
{
}

public interface ICommand<TResponse> : IMessage<TResponse>
{
}

public class MyCommand : ICommand<CommonResponse>
{
}
public interface IMessageHandler<in TRequest, TResponse> 
    : MediatR.IRequestHandler<TRequest, TResponse> 
        where TRequest : IRequest<TResponse>
{
}

public interface ICommandHandler<in TRequest, TResponse> 
    : IMessageHandler<TRequest, TResponse> 
        where TRequest : IRequest<TResponse>
{
}

public class MyCommandHandler : ICommandHandler<MyCommand, CommonResponse>
{
    public async Task<CommonResponse> Handle(
        MyCommand request, 
        CancellationToken cancellationToken)
    {
        Debug.WriteLine("   ***** Command handler executing *****");

        return
            new CommonResponse(
                succeeded: true,
                data: "Command execution completed successfully.");
    }
}
我正在试验这两种方法,通用和非通用:

public class MyCommandPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
{
    public Task Process(TRequest request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
        return Task.CompletedTask;
    }
}

- AND -

public class MyCommandPreProcessor : IRequestPreProcessor<IRequest<ICommonResponse>>
{
    public Task Process(TRequest request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("***** MYCOMMAND PREPROCESSOR CALLED *****");
        return Task.CompletedTask;
    }
}
公共类MyCommand预处理器:IRequestPreProcessor
{
公共任务流程(TRequest请求、CancellationToken CancellationToken)
{
WriteLine(“******MYCOMMAND”和名为******”的预处理器);
返回Task.CompletedTask;
}
}
-及-
公共类MyCommand预处理器:IRequestPreProcessor
{
公共任务流程(TRequest请求、CancellationToken CancellationToken)
{
WriteLine(“******MYCOMMAND”和名为******”的预处理器);
返回Task.CompletedTask;
}
}
继承结构

// Requests

IMediatR.IRequest<TResponse>
    <- IMessage<TResponse>
        <- ICommand<TResponse>
            <- concrete MyCommand : ICommand<CommonResponse>
        <- IQuery<TResponse>
            <- concrete MyQuery : IQuery<CommonResponse>

// Request Handlers

IMediatR.IRequestHandler<in TRequest,TResponse>
    <- IMessageHandler<in TRequest,TResponse>
        <- ICommandHandler<in TRequest,TResponse> 
            <- concrete MyCommandHandler : ICommandHandler<MyCommand,CommonResponse>
        <- IQueryHandler<In TRequest,TResponse>
            <- concrete MyQueryHandler : IQueryHandler<MyQuery,CommonResponse>

// CommonResponse - A POCO that returns result info

ICommonResponse
    <- concrete CommonResponse
public interface IMessage<TResponse> : MediatR.IRequest<TResponse>
{
}

public interface ICommand<TResponse> : IMessage<TResponse>
{
}

public class MyCommand : ICommand<CommonResponse>
{
}
public interface IMessageHandler<in TRequest, TResponse> 
    : MediatR.IRequestHandler<TRequest, TResponse> 
        where TRequest : IRequest<TResponse>
{
}

public interface ICommandHandler<in TRequest, TResponse> 
    : IMessageHandler<TRequest, TResponse> 
        where TRequest : IRequest<TResponse>
{
}

public class MyCommandHandler : ICommandHandler<MyCommand, CommonResponse>
{
    public async Task<CommonResponse> Handle(
        MyCommand request, 
        CancellationToken cancellationToken)
    {
        Debug.WriteLine("   ***** Command handler executing *****");

        return
            new CommonResponse(
                succeeded: true,
                data: "Command execution completed successfully.");
    }
}
//请求
iMedia.IRequest

我有相同的场景a