1

我需要在每个请求开始时提取几个标头值,并将它们放入一个 ClientContext 对象中,MEF 可以将该对象注入我的应用程序代码中。我正在使用 WCF Web API 的预览版 5,但看不到这样做的方法。

在“标准”WCF 中,我将创建一个实现 IExtension<OperationContext> 的类,并具有以下属性将它们连接在一起:

[Export(typeof(IClientContext)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public static ClientContextExtension Current
{
    get
    {
        var operationContext = OperationContext.Current;

        if (operationContext == null)
            return null;

        var extension = operationContext.Extensions.Find<ClientContextExtension>();

        if (extension == null)
        {
            extension = new ClientContextExtension();

            operationContext.Extensions.Add(extension);
        }

        return extension;
    }
}

自定义 DelegatingHandler 调用 ClientContextExtension.Current 并根据标头值设置属性。不幸的是,使用 WCF Web API,OperationContext.Current 始终为空!

我想不出一种方法来使它与 Web API 一起工作。任何帮助表示赞赏!

4

2 回答 2

1

我提出了一个可行的解决方案,但对其他选择持开放态度。首先,原始方法背后的一些基本原理......

因为 WCF 使用线程池,所以基于每线程模型的任何东西都可能(并且将会)具有超出单个请求的生命周期。我需要一种方法来存储从每个请求的 HTTP 标头中提取的客户端上下文信息,因为每次信息都会不同。这意味着我不能保留每个线程的上下文信息,因为线程将被重用。

或者我可以吗?

我的逻辑中的缺陷是线程重用是问题所在。实际上,每个线程一次只为单个请求提供服务,从而使该线程中的任何信息都与该请求隔离。因此,我需要做的就是确保信息与该请求相关并且我的问题得到解决。

我的解决方案是重构 Current 属性以引用标有 [ThreadStatic()] 属性的私有静态字段,确保每个实例都特定于线程。然后,在为每个请求执行的 DelegatingHandler 中,我为该请求重置对象的属性。在该请求期间对 Current 的后续调用返回特定于请求的信息,并且线程处理的下一个请求在 DelegatingHandler 中更新,因此就我的其他代码而言,上下文是每个请求的。

不完美,但它至少让我暂时启动并运行。正如我所说,我对其他解决方案持开放态度。

更新

经过仔细检查,该解决方案不起作用,因为 DelegatingHandler 和使用上下文对象的服务代码之间没有线程关联。结果,有时我对检索 ThreadStatic 对象的调用按预期工作,但在其他情况下,我得到一个新实例,因为代码在与处理程序不同的线程上运行。

所以,忽略这个解决方案。回到绘图板。

更新我的更新

在与 Glenn Block 讨论了我的问题后,事实证明这只是确保在请求处理程序(服务)正在执行的同一线程上设置上下文的问题。解决方案是使用 HttpOperationHandler 而不是 MessageHandler。

根据 Glenn 的说法,消息处理程序是异步操作的,这意味着它们可以在与请求处理程序(服务)不同的线程上执行,因此我们永远不应该在需要线程关联的消息处理程序中做任何事情。另一方面,操作处理程序与请求处理程序在同一线程上同步运行,因此我们可以依赖线程亲和性。

所以,我只是将我的代码从 MessageHandler 移动到 HttpOperationHandler 并获得所需的结果。

你可以在这里阅读完整的解释:http: //sonofpirate.blogspot.com/2011/11/modeling-client-context-in-wcf-web-api.html

于 2011-11-16T13:23:13.073 回答
0

您可以尝试使用

HttpOperationHandler<HttpRequestMessage, HttpRequestMessage>

在那里你应该能够访问标题。

于 2011-11-11T18:36:28.087 回答