在我的开发团队中,我们使用 this article 中描述的 CQRS 模式。并使用推荐 DI 容器:Simple Injector (双关语)。
这是我们当前的项目结构:
- 01 WebApp
引用 => [02] [03]
- 02契约(Contract)
- 03 业务层
项目 01 是客户端(一个 ASP.NET MVC 4 应用程序),我们在其中使用简单注入(inject)器 (Bootstrapper
) 注册应用程序的服务。项目 03 是定义所有命令和查询处理程序的地方,如本文所述。项目 02 是定义命令和查询的地方。为了让简单注入(inject)器注册处理程序,客户端可以直接引用业务层程序集。
容器像这样注册命令处理程序
container.Register(typeof(ICommandHandler<>), assemblies);
现在的问题是,我们的一位开发人员不小心忘记将他的处理程序类之一声明为public
。所以代替:
public class AddCustomerCommandHandler : ICommandHandler<AddCustomerCommand> { ... }
他写道:
class AddCustomerCommandHandler : ICommandHandler<AddCustomerCommand> { ... }
现在根据msdn ,如果省略访问修饰符,则使用内部:
Classes and structs that are declared directly within a namespace (in other words, that are not nested within other classes or structs) can be either public or internal. Internal is the default if no access modifier is specified.
现在内部定义为:
The type or member can be accessed by any code in the same assembly, but not from another assembly.
尝试执行此命令后,运行时不会抛出任何错误,并且命令会愉快地执行。我对此感到惊讶,因为我预计简单注入(inject)器会出现验证错误,但事实并非如此。此外,当尝试从客户端内部直接实例化处理程序对象时,编译器会给出一个错误,指出它无法按预期访问此处的内部类!那么为什么简单注入(inject)器能够注册这个命令处理程序,而它的访问修饰符是internal
?
最佳答案
在以前的版本中,Simple Injector 的批量注册默认跳过内部类型,并且有一个标志允许您也注册内部类型。
这种方法已被证明是有问题的,因为在某些应用程序中,缺少的类型允许应用程序继续运行,同时显示出不正确的行为(从而静默失败)。
为了防止这种情况发生,我们更改了此行为,现在您也将始终看到此类类型被注册。这个想法是,默默地跳过预期的类型比其他任何事情都糟糕得多。由于大多数应用程序在完全信任的情况下运行,因此可以构造和解析内部类型,因此从简单注入(inject)器的角度来看,类型是内部的就很好。对于其他应用程序类型,调用Verify将快速检测到不可构造的类型。
同样从应用程序的角度来看,类型是内部的应该没有问题,因为使用者与该类型实现的公共(public)接口(interface)进行通信。
在您的情况下失败的原因很可能是因为您调度处理程序并在调度期间使用动态
类型。在我看来,您所看到的是 C# 动态基础架构中的一个怪癖。 C# 尝试使用反射查找 Handle
方法,但 Handle 方法是内部方法,因为它的周围类型是内部类型。即使该类型实现了包含该方法的公共(public)接口(interface),它也找不到该方法。这是一个怪癖,我相信 C# 仍然应该找到该方法;但事实并非如此。这就是您的代码失败的原因。
您可以采取多种措施来防止将来出现此类问题。例如,您可以定义一个单元测试来检查所有处理程序是否都是公共(public)的。或者,您可以定义一个特殊的通用和公共(public)包装类,并将处理程序作为构造函数参数,并解析该包装程序而不是处理程序。然后,您可以在该包装器上使用动态类型。或者您注册一个最外层的装饰器,并确保它是公共(public)的。 C# 反射(reflect)了最外层的类型,因此这可以工作。
您还可以将检查集成到简单注入(inject)器中,在其中有条件地注册最外层装饰器,并让谓词在处理程序是内部的情况下抛出异常。
关于c# - 简单注入(inject)器注册并执行内部CommandHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38245451/