2

我正在使用一个使用 Unity (v2.0) 作为 Microsoft Enterprise Library 一部分的应用程序。它被设置为您可以在方法的顶部添加一个属性,并且在方法执行之前会完成一些事情(跟踪/记录/缓存等)。下面的示例代码:

static void Main(string[] args)
{
    IUnityContainer myContainer = new UnityContainer()
        .AddNewExtension<Interception>()
        .RegisterType<IFoo, Foo>(
            new Interceptor<InterfaceInterceptor>(),
            new InterceptionBehavior<PolicyInjectionBehavior>()
        );
    IFoo myFoo = myContainer.Resolve<IFoo>();

    myFoo.fooMethodCall();
}

public class TraceAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new TraceCallHandler();
    }
}

public class TraceCallHandler : ICallHandler
{
    public int Order { get; set; }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        IMethodReturn methodReturn;
        //Do tracing/chaching/other funky stuff
        methodReturn = getNext()(input, getNext);       
        return methodReturn;
    }
}

public interface IFoo
{
    int fooMethodCall();
}

public class Foo : IFoo
{
    [Trace]
    public int fooMethodCall()
    {
        return 0;
    }
}

现在,我对这种工作方式有两个烦恼,一个非常严重的问题。第一个烦恼是生成的堆栈跟踪的大小看这里。尝试调试 5 级深度的函数会导致一些难以导航的可怕堆栈跟踪。

第二个烦恼是使用VS2010调试的时候,似乎无法进入fooMethodCall. 尝试介入会导致与我尝试跨过方法调用相同的行为。

我遇到的实际问题是错误处理。想象一下,我更改fooMethodCall为以下内容:

public int fooMethodCall()
{
    throw new Exception();
}

并这样称呼它:

try 
{
    myFoo.fooMethodCall();
} 
catch Exception(e)
{
    //do something with the exception
}

如果我检查 e.StackTrace,它是最无用的:

at DynamicModule.ns.Wrapped_IFoo_dd88617b4f734f1987dc0099d195ca52.fooMethodCall()
at ConsoleApplication1.Program.Main(String[] args) 
in C:\Projects\ConsoleApplication1\Program.cs:line 152

这一切告诉我的是 fooMethodCall 失败了。它可能在一开始就失败了,或者在嵌套 5 层的方法中失败了。

那么关于这个的几个问题。这段代码看起来对吗?如果是这样,我列出的烦恼/问题是否在拦截方法调用时是不可避免的?有没有更好的方法来做我想要实现的目标?

4

2 回答 2

2

我在这里问了同样的问题: Unity 调用站点拦截方法的完整堆栈跟踪,并提供了这个线程:在 C# 中,如何在不丢失堆栈跟踪的情况下重新抛出 InnerException?

我们最终添加了另一个拦截器,它最终成为管道中第一个使用第二个链接中的技术保留跟踪的拦截器。我承认,总体而言,这有点巫术和不好的做法,但我们不太担心获得完整的堆栈跟踪。

于 2012-08-30T22:20:35.720 回答
2

只需将返回值的异常设置为新的异常即可。例如:

public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
    IMethodReturn r = getNext()(input, getNext);
    if (r.Exception != null) r.Exception = new Exception("NameOfInterceptor", r.Exception);
    return r;
}
于 2014-03-31T16:39:54.657 回答