AOP与Autofac和DynamicProxy2异常处理
本文关键字:DynamicProxy2 异常处理 Autofac AOP | 更新日期: 2023-09-27 18:08:11
我正试图集中管理某个方法的异常处理,但我似乎无法到达那里。
public class ExceptionInterceptor : IInterceptor
{
private readonly Logger _logger;
public ExceptionInterceptor(Logger logger)
{
_logger = logger;
Measure.Configure(new StatsdConfig());
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
//if ((Task<System.Threading.Tasks.VoidTaskReturn>) invocation.ReturnValue.Status == "Failed")
//{
// throw new Exception(invocation.ReturnValue.Exception[0]);
//}
}
catch (Exception e)
{
var errorMessage =
String.Format(
"An error occurred while retrieving fund data. Error Message: {0} Inner Exception: {1}",
e.Message, e.InnerException != null ? e.InnerException.Message : "<None>");
_logger.Log(errorMessage);
Measure.Counter("Exception", 1);
Measure.Event("Exception", errorMessage);
throw;
}
}
我把它连接在一个模块中,像这样:
builder.RegisterType<DataConsumer>().
As<IConsumer<DataRequest>>().
EnableInterfaceInterceptors().
InterceptedBy(typeof(ExceptionInterceptor));
builder.RegisterType<ExceptionInterceptor>().AsSelf();
var loggingInterceptor = new LoggingInterceptor(Logger);
builder.Register(c => loggingInterceptor);
然而,当我在方法调用中抛出异常时,它不会作为抛出的异常冒泡到拦截器中,因此它永远不会进入catch块。是否有任何方法可以在拦截器中捕获被拦截方法的异常?
由于某些原因,我也无法访问invoke . returnvalue . status,因此无法测试是否有抛出异常以便重新抛出。
有谁能告诉我我在这里可能没有做什么吗?
Ta
由于信息不完整,我很难再现您的问题。例如,您注意到IConsumer<T>
接口是MassTransit接口,但MassTransit中的接口不是通用的。它还特别提到接口应该是IoC容器的标记,这可能对您的连接有一些影响。
首先,让我们发布一个工作异常处理示例。为了实现自包含,我将创建一个IWorker<T>
接口来代替IConsumer<T>
和一个简单的实现:
public interface IWorker<T>
{
bool DoWork(T message);
}
public class StringWorker : IWorker<string>
{
public bool DoWork(string message)
{
throw new DivideByZeroException();
}
}
现在我将创建一个简单的异常日志记录器,它将信息传输到控制台。
public class ExceptionLogger : IInterceptor
{
private readonly TextWriter _output;
public ExceptionLogger(TextWriter output)
{
_output = output;
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
}
catch(Exception ex)
{
_output.WriteLine("Logged Exception: {0}", ex.Message);
throw;
}
}
}
我可以把它连接起来,看看它是如何工作的,像这样:
var builder = new ContainerBuilder();
builder.RegisterInstance(Console.Out).As<TextWriter>();
builder.RegisterType<ExceptionLogger>();
builder.RegisterType<StringWorker>()
.As<IWorker<string>>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(ExceptionLogger));
var container = builder.Build();
var worker = container.Resolve<IWorker<string>>();
worker.DoWork("Test!");
当我运行这个时,我在控制台中看到,就在程序结束之前(带有未处理的异常-注意我的处理程序没有吞下它,只是记录了它):
Logged Exception: Attempted to divide by zero.
运行正常
我认为你的环境中可能有更多的东西会在这里造成麻烦。可能是你认为不相关但实际上很重要的事情。
一般调查事项:
- 临时更新您的
- 查看您期望看到日志记录发生的地方。你是解决和工作与
IConsumer<DataRequest>
或其他东西?它包装了接口方法,而不是对象类型,所以不是所有的方法都被覆盖。 - 在拦截器中设置一个断点,看看是否有任何调用通过它。如果没有命中,它不会捕获异常。:)
- 检查是否有其他异常处理策略或代码在运行。例如,有些人使用Enterprise Library异常处理块来处理异常,这可能会干扰您在这里的工作。
- 我没有使用MassTransit,但检查看看是否有任何其他对象代理正在进行。(值得怀疑,但我知道我在使用像Glimpse这样的产品时遇到过这种情况,所以你最终会用代理包裹代理,这变得很有挑战性。)
- 异常真的发生在你认为的地方吗?它可能在某个地方发生并被处理,而不是被代理包装。
DataConsumer
以立即在其中一个接口方法中抛出异常。在构建容器之后,解析a、IConsumer<DataRequest>
并调用该接口方法。它会被记录吗?基本上,将工件减少到尽可能小的集合,直到你可以看到它工作,然后慢慢扩大,直到你找到它坏的地方。我不知道这些是否适用于你的情况,但如果我在排除故障,这些都是我开始关注的事情。
但是…使用拦截器以AOP方式处理异常确实可以工作,所以引起挑战的是其他事情。
似乎不可能将目标代理中抛出的异常推到拦截器,因此我试图做的事情不起作用。我最终在异常发生的类上处理异常。
很失望,我没能让它按我想要的方式工作。