5

We're looking into using Unity to handle logging service methods with interception. However, one concern is that the full stack trace is not available at the call site; its only available within an interceptor call.

Here's an example setup:

public interface IExceptionService
{
    void ThrowEx();
}

public class ExceptionService : IExceptionService
{
    public void ThrowEx()
    {
        throw new NotImplementedException();
    }
}

public class DummyInterceptor : IInterceptionBehavior
{
    public IEnumerable<Type> GetRequiredInterfaces()
    {
        return Type.EmptyTypes;
    }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {
        IMethodReturn ret = getNext()(input, getNext);
        if (ret.Exception != null)
            Console.WriteLine("Interceptor: " + ret.Exception.StackTrace + "\r\n");
        return ret;
    }

    public bool WillExecute
    {
        get { return true; }
    }
}

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.AddNewExtension<Interception>();

        container.RegisterType<IExceptionService, ExceptionService>(
            new Interceptor<InterfaceInterceptor>(),
            new InterceptionBehavior<DummyInterceptor>());

        try
        {
            container.Resolve<IExceptionService>().ThrowEx();
        }
        catch (Exception e)
        {
            Console.WriteLine("Call Site: " + e.StackTrace);
        }

    }
}

Here's the console output from running that program:

Interceptor:
at ConsoleDemo.ExceptionService.ThrowEx() in    C:\code\ServiceDemo\ConsoleDemo\Program.cs:line 25
at DynamicModule.ns.Wrapped_IExceptionService_248fe3264f81461f96d34670a0a7d45d.<ThrowEx_DelegateImplementation>__0(IMethodInvocation inputs, GetNextInterceptionBehaviorDelegate getNext)

Call Site:
at DynamicModule.ns.Wrapped_IExceptionService_248fe3264f81461f96d34670a0a7d45d.ThrowEx()
at ConsoleDemo.Program.Main(String[] args) in C:\code\ServiceDemo\ConsoleDemo\Program.cs:line 63

The stack trace in the interceptor is fine and will suffice for logging at the service level. However, we lose everything past the interception proxy call at the call site;

I can wrap the exception in the interceptor in a ServiceException or some such, and that will keep the call stack in the inner exception, but that leads to awkward logging and debug inspection scenarios (though less awkward than losing the trace entirely).

I've also noticed we get more or less what we want when we use the TransparentProxyInterceptor, but that is noted as being slower than InterfaceInterception, and that triggers alarm bells for some groups.

Is there any cleaner way to get a full stack trace with Unity interception at the call site on a proxy?

Adi Lester
  • 24,731
  • 12
  • 95
  • 110
Nick
  • 513
  • 3
  • 9

1 Answers1

2

In .NET 4.5 there will be ExceptionDispatchInfo for this purpose.

For all other versions you can see this question:
In C#, how can I rethrow InnerException without losing stack trace?

Community
  • 1
  • 1
Andrey Shchekin
  • 21,101
  • 19
  • 94
  • 162
  • 1
    @Nick - can you say more what you ended up doing? – Robert Ivanc Mar 21 '14 at 16:24
  • I don't have access to that code anymore, but it was passing `ret.Exception` in my original question to the example methods from the SO link in the accepted answer (effectively `PreserveStackTrace(ret.Exception)` from [here](http://stackoverflow.com/a/2085377)). I did also try the reflection based approach later in the comment string, which was working on .NET 4.0. If we had moved to .NET 4.5 while I was still working on it, I would've looked into using ExceptionDispatchInfo instead. – Nick Mar 22 '14 at 18:59
  • In my case, using ExceptionDispatchInfo works in Debug mode but not in Release mode. Any reason for that? – rlesias Jan 28 '19 at 12:54