通过DI和测试使WCF OperationContext很好地发挥作用

时间:2011-07-12 23:40:31

标签: wcf dependency-injection unity-container operationcontext

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

最近,我在服务中添加了一些功能,它使用OperationContext来检查传入的消息。不幸的是,由于微软对密封和/或静态类的缺乏以及缺乏接口和/或虚拟方法,这使得服务的可测试性降低了。

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

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

container.RegisterType<IOperationContext, OperationContextWrapper>(new InjectionConstructor(OperationContext.Current));

但此时OperationContext.Currentnull,因此Unity会立即抛出异常,而我在40岁之前退休的梦想也会消失。

所以,问题是:你如何让WCF与DI和OperationContext包裹得很好?

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

OperationContext.Current是一个可设置的属性。您可以将测试初始化​​更改为

OperationContext.Current = new OperationContextWrapper();

并以这种方式工作?如果你需要统一,你也可以:

var oc = new OperationContextWrapper();
OperationContext.Current = oc;
container.RegisterInstance<IOperationContext>(oc);

答案 2 :(得分:1)

您还可以使用Microsoft Fakes:

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

OperationContext.Current = shimOperationContext;
}