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 :)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…