使WCF OperationContext与DI和测试配合良好

使WCF OperationContext与DI和测试配合良好,wcf,dependency-injection,unity-container,operationcontext,Wcf,Dependency Injection,Unity Container,Operationcontext,我正在运行Windows服务中托管的WCF服务;WCF服务的依赖项是通过Unity注入的,这很好。因此,该服务也很容易为其编写单元测试 最近,我向服务添加了使用OperationContext检查传入消息的功能。不幸的是,由于微软对密封类和/或静态类的喜爱,以及缺乏接口和/或虚拟方法,这使得服务的可测试性大打折扣 因此,在这种情况下,我转向.NET最喜欢的工具,一个包装器类。因为这是一个常见的问题,所以有些人的。因此,这为我的WCF服务(IOperationContext的实现)添加了一个新的依

我正在运行Windows服务中托管的WCF服务;WCF服务的依赖项是通过Unity注入的,这很好。因此,该服务也很容易为其编写单元测试

最近,我向服务添加了使用OperationContext检查传入消息的功能。不幸的是,由于微软对密封类和/或静态类的喜爱,以及缺乏接口和/或虚拟方法,这使得服务的可测试性大打折扣

因此,在这种情况下,我转向.NET最喜欢的工具,一个包装器类。因为这是一个常见的问题,所以有些人的。因此,这为我的WCF服务(IOperationContext的实现)添加了一个新的依赖项。这对我的单元测试来说没有问题,NSubstitute是我选择的模拟框架(像Moq一样,但没有
.Object
的诅咒)

但是,当我尝试真正启动服务时,我遇到了以下问题-在完成IoC容器注册时,正在包装的OperationContext尚未初始化。我的初始化代码(此处使用Unity)是:

container.RegisterType(新的InjectionConstructor(OperationContext.Current));
但此时,
OperationContext.Current
null
,因此Unity立即抛出了一个异常,我40岁之前退休的梦想化为泡影


因此,问题是:如何让WCF与DI和包装的
OperationContext

OperationContext配合使用。当前的
是一个可设置的属性。您可以将测试初始化更改为

OperationContext.Current = new OperationContextWrapper();
那它是这样工作的吗?如果您需要统一,您还可以:

var oc = new OperationContextWrapper();
OperationContext.Current = oc;
container.RegisterInstance<IOperationContext>(oc);
var oc=new OperationContextWrapper();
OperationContext.Current=oc;
容器注册状态(oc);

也许我不理解,但我不确定您为什么要将OperationContext.Current注入到包装器中。如果OperationContextWrapper正在包装OperationContext,那么为什么不让它的实现直接与OperationContext.Current交互呢?我假设您试图保持可测试性的代码不是OperationContextWrapper,而是通过IOperationContext接口依赖它的代码?那么谁在乎OperationContextWrapper做什么呢?

您也可以使用Microsoft Fakes:

using (ShimsContext.Create()) 
{
ShimOperationContext shimOperationContext = new
ShimOperationContext(); shimOperationContext.SessionIdGet = () => "sessionId";

OperationContext.Current = shimOperationContext;
}

但在本例中,OperationContextWrapper是围绕OperationContext.Current包装的,因此您可以将其称为:OperationContextWrapper context=new OperationContextWrapper(OperationContext.Current);这大致就是我的Unity代码试图实现的目标。最后,我在OperationContextWrapper上使用了poor man的DI,创建了一个默认构造函数,将OperationContext.Current注入到其更常见的构造函数中,然后指示Unity使用默认构造函数,而不是具有依赖性的构造函数。现在,服务启动正常,在运行时使用OperationContext.Current,在单元测试中使用模拟对象。
using (ShimsContext.Create()) 
{
ShimOperationContext shimOperationContext = new
ShimOperationContext(); shimOperationContext.SessionIdGet = () => "sessionId";

OperationContext.Current = shimOperationContext;
}