我在.NET Framework 4.8(WCF(中有一个应用程序可以进行http调用,也可以使用Polly进行重试和回退管理,但有时会引发System.NullReferenceException
,但我不知道问题出在哪里。这是代码:
private static async Task<bool> CallApi<TRequest>(TRequest request, string requestUri, Func<string, StringContent, Task<HttpResponseMessage>> func)
{
var jsonRequest = JsonConvert.SerializeObject(request);
var fallBackPolicy = Policy<HttpResponseMessage>.Handle<Exception>()
.FallbackAsync(new HttpResponseMessage(HttpStatusCode.SeeOther)
{
Content = new StringContent($"Exception has occurred in migration call. RequestUri: {requestUri}")
},
result =>
{
LogEventService.Logger.Error(result.Exception, "An unhandled exception occurred while retrying calling");
return Task.CompletedTask;
});
var waitAndRetryPolicy = Policy.HandleResult<HttpResponseMessage>(res => res.StatusCode == HttpStatusCode.InternalServerError).
WaitAndRetryAsync(2, retryAttempts => TimeSpan.FromMilliseconds(500));
var response = await fallBackPolicy
.WrapAsync(waitAndRetryPolicy)
.ExecuteAsync(async () =>
{
using (var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json"))
{
content.Headers.Add("X-Correlation-ID", HttpContext.Current.Session[RequestId].ToString());
return await func(requestUri, content);
}
});
if(response.IsSuccessStatusCode)
return true;
await LogMessage(LogLevel.Error, response, requestUri);
return false;
}
这是StackTrace
System.NullReferenceException:对象引用未设置为实例对象的
在UserMigrationService<gt;c_DisplayClass22_0'1。<b_3>d.MoveNext((在里面…\Services\UserMigrationService.cs:line 474
---从引发异常的前一位置开始的堆栈跟踪结束---
位于System.Runtime.ExceptionServices.ExceptionDispatchInfo.Sthrow((
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Sthrow((处的
atPolly.Retry.AsyncRetryEngine.d_0'1.MoveNext((
---从引发异常的前一位置开始的堆栈跟踪结束---
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务(处的
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Sthrow((处的
Polly.AncurrentPolicy'1.d_13.MoveNext((
---从引发异常的前一位置开始的堆栈跟踪结束---
<blockquote\>位于System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务(处的
Polly.Wrapa.AsyncPolicyWrapEngine。<gt;c__DisplayClass0_0'1。<b_ 0>d.MoveNext((
---从引发异常的前一位置开始的堆栈跟踪结束---
在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Sthrow((>在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务(
Polly.Fallback.AsyncFallbackEngine.d_0'1.MoveNext((
你能帮我找出错误的零件在哪里吗?我怎样才能更好地理解为什么抛出此异常
感谢所有
事实证明,NRE是在这一行抛出的:
ontent.Headers.Add("X-Correlation-ID", HttpContext.Current.Session[RequestId].ToString());
这表明CCD_ 2可能是CCD_。ExecuteAsync
接收一个委托,该委托可能与CallApi
方法的其余代码不在同一线程上运行。
这就是HttpContext
不会流入代理的原因。
修复非常简单:您必须在CallApi
中捕获RequestId
,而不是在ExecuteAsync
委托中捕获:
var correlationId = HttpContext.Current.Session[RequestId].ToString();
var response = await fallBackPolicy
.WrapAsync(waitAndRetryPolicy)
.ExecuteAsync(async () =>
{
using (var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json"))
{
content.Headers.Add("X-Correlation-ID", correlationId);
return await func(requestUri, content);
}
});
我还建议使用Policy.Wrap
(参考(,而不是对其中一个策略调用WrapAsync
方法。以下两行是等效的:
fallBackPolicy.WrapAsync(waitAndRetryPolicy)
Policy.WrapAsync(fallbackPolicy, waitAndRetryPolicy)
所以,你的代码可以这样重写:
var correlationId = HttpContext.Current.Session[RequestId].ToString();
var strategy = Policy.WrapAsync(fallbackPolicy, waitAndRetryPolicy);
var response = await strategy
.ExecuteAsync(async (ct) =>
{
using (var content = new StringContent(jsonRequest, Encoding.UTF8, MediaTypeNames.Application.Json))
{
content.Headers.Add("X-Correlation-ID", correlationId);
//TODO: pass the cancellationToken to the func
return await func(requestUri, content);
}
}, CancellationToken.None);
我使用了ExecuteAsync
的另一个过载,您正在接收CancellationToken
。当您考虑使用超时策略时,这可能非常有用。在这种情况下,您应该将该令牌传递给func
函数。