使用WCF从该AspNetSynchronizationContext托管在IIS [英] Using the AspNetSynchronizationContext from WCF hosted in IIS

查看:154
本文介绍了使用WCF从该AspNetSynchronizationContext托管在IIS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在IIS托管我的.NET 4.5 WCF服务。
有被存储在所述OperationContext.Current实例一块被称为BusinessContext(BC)的信息,以便任何逻辑下游可以达到它

一切工作正常,直到我介绍了异步/在等待着,我跑进<一个href=\"http://stackoverflow.com/questions/12797091/operationcontext-current-is-null-after-first-await-when-using-async-await-in-wcf\">this发行。 @斯蒂芬 - 克利里提到的ASP.NET使用异步友好AspNetSynchronizationContext保持HttpContext.Current跨线程。由于我主持在IIS我想我应该能利用AspNetSyncCtx在WCF中,并使用HttpContext.Current代替的OperationContext来存储BC。

默认情况下,在Web.config UseTaskFriendlySynchronizationContext =真实aspNetCompatibilityEnabled = true设置:

我创建了一个从无到有的WCF服务,其中有targetFramework = 4.5,ASPNET。我还添加了AspNetCompatibilityRequirements =需要我的服务。

在运行时我看到HttpContext.Current是存在的,但SynchronizationContext.Current为空。后等待的HttpContext变成零,这是意料之中的,因为没有SyncCtx。不应该要求aspcompatibility当它被设置为AspNetSyncCtx?如何在AspNetSyncCtx得到ASP.NET设置?

- 可能的解决方法

继@斯蒂芬 - 克利里的<一个href=\"http://stackoverflow.com/questions/12797091/operationcontext-current-is-null-after-first-await-when-using-async-await-in-wcf\">here我继续定义了自定义的SynchronizationContext为preserve的的OperationContext跨线程。

我想听听社会对这个实现输入。谢谢你。

公共类OperationContextSynchronizationContext:的SynchronizationContext
{
    公共覆盖无效后(SendOrPostCallback D,对象状态)
    {
        的OperationContext opCtx = OperationContext.Current;
        InternalState internalState =新InternalState()
        {
            OpCtx = opCtx,
            回调= D,
            状态=的状态,
            SyncCtx =此
        };
        ThreadPool.QueueUserWorkItem(新WaitCallback(InternalInvoker),internalState);
    }
    私人无效InternalInvoker(对象internalState)
    {
        InternalState internalSt = internalState为InternalState;
        SynchronizationContext.SetSynchronizationContext(internalSt.SyncCtx);
        使用(新OperationContextScope(internalSt.OpCtx))
        {
            internalSt.Callback.Invoke(internalSt.State);
        }
    }
    私有类InternalState
    {
        公众的SynchronizationContext SyncCtx {搞定;组; }
        公众的OperationContext OpCtx {搞定;组; }
        公共SendOrPostCallback回调{搞定;组; }
        公共对象状态{搞定;组; }
    }
}


解决方案

我跑进了问题,你提到的(错误?)其中 HttpContext.Current 没有在<流code>异步 code在IIS托管的WCF服务甚至与 aspNetCompatiblity 启用和必需的。

我使用 LogicalCallContext CallContext.LogicalSetData CallContext中我的项目。 LogicalGetData 这博客文章。我想设置/获取您的业务环境正是如此会工作你的情况非常好,可能是重量更轻,比概念自定义的SynchronizationContext 简单。在你的情况你不得不反正某处设置你的业务环境......还不如将其设置为 LogicalCallContext ,我相信一切都会好起来的。

我会解释我个人的解决方案更详细的,虽然我承认这是一个有点哈克,因为我手动流动的整个的HttpContext 对象(也是唯一的在WCF方法)。但是,再次与您的自定义上下文对象你的情况,似乎是更好的选择。

在我继承了ASP.NET Web应用程序,有整个业务逻辑(不理想)散落调用 HttpContext.Current 。显然,项目运行良好,直到我想几个应用中的WCF方法是异步

很多业务逻辑的话费会从ASP.NET页面加载,等等,这里的一切功能罚款,因为它是。

我解决(kludged?)我的问题在.NET 4.5通过创建一个小的辅助类 ContextHelper ,并更换 HttpContext.Current所有通话 ContextHelper.CurrentHttpContext

 公共类ContextHelper
{
    公共静态无效prepareHttpContextFlow()
    {
        CallContext.LogicalSetData(CurrentHttpContext,HttpContext.Current);
    }    公共静态的HttpContext CurrentHttpContext
    {
        得到
        {
            返回HttpContext.Current?
                   CallContext.LogicalGetData(CurrentHttpContext)
                   为HttpContext的;
        }
    }
}

现在随时在 HttpContext.Current 的定义,帮助我的方法本质上是一个空操作。

要完成这项工作,我的WCF调用必须在第一次调用的await prepareHttpContextFlow 方法的入口点code>这是无可否认的问题的,主要的原因我认为这是一个杂牌组装电脑。

在我的情况下,这个缺点是,我需要一些其他手动调用添加逻辑堆栈信息对于正在使用时,会丢失添加错误日志记录上下文中的事实,缓解异步 (因为在异常的物理堆栈信息不是错误日志非常有用在这种情况下)。因此,至少如果我记得做了prepare的异步调用之一,我要记得做其他:)

I'm hosting my .NET 4.5 WCF services in IIS. There's a piece of information called "BusinessContext" (BC) that is stored in the OperationContext.Current instance, so that any logic downstream can reach it.

Everything worked fine until I introduced async/await, and I ran into this issue. @stephen-cleary mentioned ASP.NET uses the async-friendly AspNetSynchronizationContext to keep the HttpContext.Current across threads. Since I'm hosting in IIS I figured I should be able to take advantage of the AspNetSyncCtx in WCF, and use the HttpContext.Current instead of the OperationContext to store the BC.

I created a WCF service from scratch, which has targetFramework = 4.5, aspnet:UseTaskFriendlySynchronizationContext = true and aspNetCompatibilityEnabled = true set by default in the Web.config. I also added the AspNetCompatibilityRequirements = Required to my service.

At runtime I see the HttpContext.Current is there, but SynchronizationContext.Current is null. After an await the HttpContext becomes null, which is expected because there's no SyncCtx. Shouldn't it be set to AspNetSyncCtx when aspcompatibility is required? How does the AspNetSyncCtx get set in ASP.NET?

-- Possible solution.

Following @Stephen-cleary's here I went ahead and defined a custom SynchronizationContext to preserve the OperationContext across threads.

I'd like to hear the community's input regarding this implementation. Thanks.

public class OperationContextSynchronizationContext : SynchronizationContext
{
    public override void Post(SendOrPostCallback d, object state)
    {
        OperationContext opCtx = OperationContext.Current;
        InternalState internalState = new InternalState()
        {
            OpCtx = opCtx,
            Callback = d,
            State = state,
            SyncCtx = this
        };
        ThreadPool.QueueUserWorkItem(new WaitCallback(InternalInvoker), internalState);
    }
    private void InternalInvoker(object internalState)
    {
        InternalState internalSt = internalState as InternalState;
        SynchronizationContext.SetSynchronizationContext(internalSt.SyncCtx);
        using (new OperationContextScope(internalSt.OpCtx))
        {
            internalSt.Callback.Invoke(internalSt.State);
        }
    }
    private class InternalState
    {
        public SynchronizationContext SyncCtx { get; set; }
        public OperationContext OpCtx { get; set; }
        public SendOrPostCallback Callback { get; set; }
        public object State { get; set; }
    }
}

解决方案

I ran into the issue (bug?) you mentioned where HttpContext.Current did not flow with async code in a WCF service hosted in IIS even with aspNetCompatiblity enabled and required.

I got my project working using the LogicalCallContext with CallContext.LogicalSetData and CallContext.LogicalGetData as described by Stephen Cleary in this blog post. I think setting/getting your business context thusly would work very well in your case and might be lighter weight and conceptually simpler than the custom SynchronizationContext. In your case you are having to Set your business context somewhere anyway ... might as well set it to the LogicalCallContext and I believe everything will be fine.

I'll explain my personal 'solution' in more detail, though I admit it is a bit hacky since I'm manually flowing the entire HttpContext object (and only in WCF methods). But again your case with your custom context object would seem to be a better fit.

In the ASP.NET web app I inherited, there were calls to HttpContext.Current littered throughout the business logic (not ideal). Obviously the project worked fine until I wanted several of the WCF methods in the app to be async.

A lot of the calls in the business logic would be from ASP.NET page loads, etc, where everything functions fine as it is.

I solved (kludged?) my problem in .NET 4.5 by creating a little helper class ContextHelper, and replaced all calls to HttpContext.Current with ContextHelper.CurrentHttpContext.

public class ContextHelper
{
    public static void PrepareHttpContextFlow()
    {
        CallContext.LogicalSetData("CurrentHttpContext", HttpContext.Current);
    }

    public static HttpContext CurrentHttpContext
    {
        get
        {
            return HttpContext.Current ?? 
                   CallContext.LogicalGetData("CurrentHttpContext") 
                   as HttpContext;
        }
    }
}

Now anytime the HttpContext.Current is defined, my helper method is essentially a no-op.

To make this work, the entry points for my WCF calls must call the PrepareHttpContextFlow method before the first call to await which is admittedly problematic and the main reason I consider this a kludge.

In my case this downside is mitigated by the fact that I have some OTHER manual calls required to add logical stack information for added error logging context that is lost when using async (since the physical stack information in an exception is not very useful for error logs in this case). So at least if I remember to do one of the "prepare for async" calls, I should remember to do the other :)

这篇关于使用WCF从该AspNetSynchronizationContext托管在IIS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆