0

按照以下示例:

MediatR.Examples.Ninject

我有一个 MediatorModule 类,如下所示:

    public class MediatorModule : NinjectModule {
        public class ContravariantBindingResolver : NinjectComponent, IBindingResolver {
            public IEnumerable<IBinding> Resolve(Multimap<Type, IBinding> bindings, Type service) {
                if (service.IsGenericType) {
                    var genericType = service.GetGenericTypeDefinition();
                    var genericArguments = genericType.GetGenericArguments();

                    if (1 == genericArguments.Count() && genericArguments.Single().GenericParameterAttributes.HasFlag(GenericParameterAttributes.Contravariant)) {
                        var argument = service.GetGenericArguments().Single();
                        var matches = bindings.Where(kvp => kvp.Key.IsGenericType
                                                         && kvp.Key.GetGenericTypeDefinition().Equals(genericType)
                                                         && kvp.Key.GetGenericArguments().Single() != argument
                                                         && kvp.Key.GetGenericArguments().Single().IsAssignableFrom(argument))
                                              .SelectMany(kvp => kvp.Value);
                        return matches;
                    }
                }

                return Enumerable.Empty<IBinding>();
            }
        }
        public override void Load() {
            Kernel.Components.Add<IBindingResolver, ContravariantBindingResolver>();
            Kernel.Bind(services => services.FromAssemblyContaining<IMediator>().SelectAllClasses().BindDefaultInterface());
            Kernel.Bind(services => services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<,>)).BindAllInterfaces());
            Kernel.Bind(services => services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(INotificationHandler<>)).BindAllInterfaces());
            Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestPreProcessorBehavior<,>));
            Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestPostProcessorBehavior<,>));
            Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestExceptionActionProcessorBehavior<,>));
            Kernel.Bind(typeof(IPipelineBehavior<,>)).To(typeof(RequestExceptionProcessorBehavior<,>));
            Kernel.Bind<ServiceFactory>().ToMethod(ctx => t => ctx.Kernel.TryGet(t));
        }
    }

在 Quick Watch over 上services.FromThisAssembly().SelectAllClasses().InheritedFrom(typeof(IRequestHandler<,>)),我可以看到正确找到了这些类。

快速观看

这是我的命令和处理程序的示例。

public class SupplierInvoice {
    public class ProcessCommand : IRequest<ProcessedTransaction> {
        public ProcessCommand(XmlDocument supplierInvoiceDocument)
            => SupplierInvoiceDocument = supplierInvoiceDocument;

        public XmlDocument SupplierInvoiceDocument { get; }
    }

    public class ProcessCommandHandler : IRequestHandler<ProcessCommand, ProcessedTransaction> {
        private readonly IXmlSerializer<SupplierInvoice> _serializer;
        private readonly IValidator<SupplierInvoice> _validator;
        private readonly IMediator _mediator;
        public ProcessCommandHandler(IXmlSerializer<SupplierInvoice> serializer, IValidator<SupplierInvoice> validator, IMediator mediator) {
            _serializer=serializer;
            _validator=validator;
            _mediator=mediator;
        }

        public async Task<ProcessedTransaction> Handle(ProcessCommand request, CancellationToken cancellationToken) {
            if (request == null) return ProcessedTransaction.Succeeded;

            var model = _serializer.Deserialize(request.SupplierInvoiceDocument.OuterXml);
            var vr = _validator.Validate(model);
            if (!vr.IsValid) // throwing exception with validation messages.

            return await _mediator.Send(new CreateCommand(model));
        }
    }
}

所以我想知道如何不使用该BindAllInterfaces方法注册处理程序?

即使使用普通的旧绑定语法,请求处理程序也不会被注册。

Kernel.Bind<IRequestHandler<SupplierInvoice.ProcessCommand, ProcessedTransaction>>().To<SupplierInvoice.ProcessCommandHandler>();

我错过了什么?

4

1 回答 1

1

根据链接的 Ninject 示例:MediatR.Examples.Ninject,我想我在ContravariantBindingResolver.cs类中发现了一个错误。

我猜有问题的那条线是第二次获取通用参数时。

var genericType = service.GetGenericTypeDefinition();
var genericArguments = genericType.GetGenericArguments();
if (genericArguments.Count() == 1
   && genericArguments.Single().GenericParameterAttributes.HasFlag(GenericParameterAttributes.Contravariant))
{
    var argument = service.GetGenericArguments().Single();
    var matches = bindings.Where(kvp => kvp.Key.IsGenericType
                                   && kvp.Key.GetGenericTypeDefinition().Equals(genericType)
                                   && kvp.Key.GetGenericArguments().Single() != argument
                                   && kvp.Key.GetGenericArguments().Single().IsAssignableFrom(argument))
                        .SelectMany(kvp => kvp.Value);
   return matches;
}

请注意,它var genericArguments = genericType.GetGenericArguments()使用service.GetGenericTypeDefinition()方法调用返回的泛型类型定义。但是因为在提供的示例代码中,第二次调用GetGenericArguments是从服务实例进行的,所以似乎没有充分返回正确的通用参数。因此,我建议使用已声明的变量,其中包含可以从中获取参数变量值的通用参数。

总而言之,对我来说,使解析器每次都能真正解析正确处理程序的原因是我更改了这一行:

var argument = service.GetGenericArguments().Single()

var argument = genericArguments.Single()

鉴于它是逆变的,所以只有可用的参数,因为已经对返回的参数数组的长度进行了检查。

为我更改此设置使未注册的处理程序异常与能够解析正确处理程序的工作代码有所不同。

于 2021-10-14T19:09:55.427 回答