当我尝试手动引发 transient 异常时,它总是作为AggregateException
处理。由于它是作为AggregateException
处理的,因此在我的重试策略中不会将其作为 transient 错误处理,也不会为预定义的重试次数进行重试。
瞬时错误显示为here。
因此,我尝试了CommunicationException
和ServerErrorException
,但将其作为AggregateException处理。
当我寻找AggregateException时,它说“代表应用程序执行期间发生的一个或多个错误”。是的,它非常有帮助!!!
这是我的案例的示例代码:
我有一个使用ServiceBusTransientErrorDetectionStrategy的重试策略
public void TestManually()
{
var retryPolicy = new RetryPolicy<ServiceBusTransientErrorDetectionStrategy>(RetryStrategy.DefaultFixed);
retryPolicy.Retrying += (obj, eventArgs) =>
{
Trace.TraceError("Hey!! I'm Retrying, CurrentRetryCount = {0} , Exception = {1}", eventArgs.CurrentRetryCount, eventArgs.LastException.Message);
};
retryPolicy.ExecuteAsync(() =>
MyTestFunction().ContinueWith(t =>
{
if (t.Exception != null)
{
// A non-transient exception occurred or retry limit has been reached
Trace.TraceError("This was not a transient exxception... It was: " + t.Exception.GetType().ToString());
}
}));
}
public Task MyTestFunction()
{
Task task = Task.Factory.StartNew(() => RaiseTransientErrorManually());
return task;
}
public void RaiseTransientErrorManually()
{
//throw new CommunicationException();
throw new ServerErrorException();
}
假设我这样调用我的函数:
TestManually();
我很困惑,为什么手动抛出的异常(定义为Transient Error)被视为AggregateException?我在那儿想念什么?
谢谢。
最佳答案
异步代码中的异常是一个棘手的问题,原因有两个。
catch
块)的方式并不总是直观的,而且似乎不一致。 我将在下面介绍每个项目。
重要说明:此答案使用术语“异步方法”来指代返回类型为
Task
或Task<T>
的任何方法。内置支持异步编程的语言有其自己的相关术语,其含义可能有所不同。异步方法引发的异常
异步方法能够在创建
Task
之前或任务本身的异步执行过程中引发异常。尽管项目在异步代码的异常记录方式上并不总是一致的,但我希望在项目中包含以下注释,以便用户清楚理解。注意:仅假设以下引用对于明确声明其状态的库为true。该声明专门用于解决上述第二个问题 Realm 。
The documentation for asynchronous methods does not distinguish between these two cases, allowing for any of the specified exceptions to be thrown in either manner.
Task
创建之前的异常在创建表示异步操作的
Task
对象之前引发的异常必须由调用代码直接捕获。例如,如果代码以这种方式抛出ArgumentNullException
,则调用代码将需要包含ArgumentNullException
或ArgumentException
的异常处理程序以处理该异常。引发直接异常的示例代码:
public Task SomeOperationAsync()
{
throw new ArgumentException("Directly thrown.");
}
处理直接引发的异常的示例代码:
try
{
Task myTask = SomeOperationAsync();
}
catch (ArgumentException ex)
{
// ex was thrown directly by SomeOperationAsync. This cannot occur if
// SomeOperationAsync is an async function (§10.15 - C# Language Specification
// Version 5.0).
}
任务执行期间的异常
在异步执行任务期间引发的异常被包装在
AggregateException
对象中,并由Exception
属性返回。以这种方式抛出的异常必须通过检查Exception
属性的任务继续处理,或者通过在包含Wait
处理程序的异常处理块内调用Result
或检查AggregateException
属性来处理。在我创建的库中,我为用户提供了额外的保证,内容如下:
注意:仅假设以下引用对于明确声明其状态的库为true。
This library additionally ensures that exceptions thrown by asynchronous operations are not wrapped in multiple layers of
AggregateException
. In other words, anArgumentException
thrown during the asynchronous execution of a task will result in theException
property returning anAggregateException
, and that exception will not contain any nested instances ofAggregateException
in theInnerExceptions
collection. In most cases, theAggregateException
wraps exactly one inner exception, which is the originalArgumentException
. This guarantee simplifies the use of the API is languages that support async/await, since those operators automatically unwrap the first layer ofAggregateException
.
在任务执行期间都会抛出异常的示例方法:
public Task SomeOperationAsync()
{
return Task.StartNew(
() =>
{
throw new ArgumentException("Directly thrown.");
});
}
public async Task SomeOtherOperationAsync()
{
throw new ArgumentException("async functions never throw exceptions directly.");
}
在任务执行期间处理异常的示例代码:
try
{
Task myTask = SomeOperationAsync();
myTask.Wait();
}
catch (AggregateException wrapperEx)
{
ArgumentException ex = wrapperEx.InnerException as ArgumentException;
if (ex == null)
throw;
// ex was thrown during the asynchronous portion of SomeOperationAsync. This is
// always the case if SomeOperationAsync is an async function (§10.15 - C#
// Language Specification Version 5.0).
}
一致的异常处理
实现异步调用期间发生的异常的特殊处理的应用程序有多个选项可用于一致处理。最简单的解决方案(如果可用)涉及使用 async / await 。这些运算符会自动解包
InnerExceptions
的AggregateException
集合中的第一个异常实例,从而导致行为似乎在调用代码时就好像异常是被调用的方法直接引发的。第二种方法涉及将原始调用视为另一项任务的延续,以确保将所有异常作为AggregateException
呈现给异常处理代码。以下代码显示了此策略在现有异步调用中的应用。请注意,CompletedTask
类和Then()
扩展方法是单独的Rackspace Threading Library(开源,Apache 2.0)的一部分。// original asynchronous method invocation
Task task1 = SomeOperationAsync();
// method invocation treated as a continuation
Task task2 = CompletedTask.Default.Then(_ => SomeOperationAsync());
使用继续策略进行一致错误处理的代码可能会受益于
Catch()
方法的使用,该方法也是Rackspace线程库的一部分。此扩展方法的行为类似于 await ,在调用处理异常的延续函数之前,会自动将InnerExceptions
的AggregateException
集合中的第一个异常实例展开。
关于c# - 为什么将人工引发的Transient Error异常作为AggregateException处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26186351/