Well, I was going to name this and a question of context, but apparently the word question isn't allowed in titles.
Anyway, here's the issue: I use IErrorHandler in my WCF services in order to provide logging without cluttering up all of my service code. Until now, this has worked great. However, now that I'm trying to move to completely asynchronous services, I'm encountering the issue of the call stack being a return stack instead of a causality chain.
Now, I tried using Stephen Cleary's logical call context MyStack, combined with Ninject's Intercept extensions..
Ninject:
Bind<IThing>().To<Thing>()
.Intercept()
.With<SimpleContextGenerator>();
SimpleContextGenerator:
public class SimpleContextGenerator : IInterceptor
{
public void Intercept(IInvocation invocation)
{
using (MyStack.Push(
string.Join(".",
invocation.Request.Method.DeclaringType.FullName,
invocation.Request.Method.Name)))
{
invocation.Proceed();
}
}
}
The problem, however, is twofold: 1) The using completes before the error actually throws, and 2) 1 doesn't even matter because the entire context is cleared out by the time I get to IErrorHandler. I can comment out the code in Pop in MyStack, and CurrentContext.IsEmpty is true when I hit ProvideFault in IErrorHandler.
So, my question is also two-part:
1) Is there a way to keep the context through to the IErrorHandler calls?
2) If not, is there another way to log errors on a global scale that does have access to the context?
I am using .NET 4.5, Ninject 3.2, and DynamicProxy 3.2.
To be honest, I'd be happy just knowing where the Exception was thrown - current class and method are enough for my purposes; the full stack isn't required.
EDIT: If I put it in the OperationContext using an IExtension<>, I can keep it around until I get to the IErrorHandler. However, I still don't know when a method ends, so I can't be sure where the exception occurred.
In order to track the stack in such a way as to be available in the
IErrorHandler, use anIExtension<>:Here's the
Framethat is being tracked:And the
Parameter:Now, you want to manage the stack using this
SimpleContextGenerator:IInterceptorhere isNinject.Extensions.Interception.IInterceptor.In order to keep the
OperationContextavailable for each call, you need to use thisOperationContextSynchronizationContext:Then you just need to hook it all up in your
Ninjectbinding:Note that this can only be applied at an interface-to-concrete-class binding, which is why we can't get the service itself into the stack in this manner. We could wrap every service method (better than wrapping every single call), but I don't think we could even do it with a module, since the service frame wouldn't have the exception for the stack walk (below).
Finally, in the
IErrorHandler:Here's the
Unpackextension method: