C# 调用HttpClient.GetAsync(url)的System.Threading.Tasks中的NullReferenceException
我的MVC4.0应用程序中有一个奇怪的问题。我使用RESTWeb服务(Amazon Associate)。我创建了一个方法,我在任何地方都使用它。缩略版本如下:C# 调用HttpClient.GetAsync(url)的System.Threading.Tasks中的NullReferenceException,c#,async-await,C#,Async Await,我的MVC4.0应用程序中有一个奇怪的问题。我使用RESTWeb服务(Amazon Associate)。我创建了一个方法,我在任何地方都使用它。缩略版本如下: private async Task<XElement> GetRequest(string url) { string myresponse; HttpResponseMessage response = null; HttpClient client = n
private async Task<XElement> GetRequest(string url)
{
string myresponse;
HttpResponseMessage response = null;
HttpClient client = new HttpClient();
try
{
response = await client.GetAsync(url);
myresponse = response.Content.ToString();
if (myresponse.Contains("503"))
{
myTrace.WriteLine("503 Sleep.....");
Thread.Sleep(3000); // looks like amazon us does not like fast requests....
return await GetRequest(url); //restart after pausing....
}
}
catch (TaskCanceledException ex)
{
myTrace.WriteLine("TaskCancelled From GetRequest: " + ex);
return null;
}
catch (HttpRequestException ex)
{
myTrace.WriteLine("RequestException Sleep.....");
Thread.Sleep(300000); // 5 minutes de pause
}
catch (Exception ex)
{
myTrace.WriteLine("From GetRequest: " + ex);
return null;
}
try
{
XElement content = await response.Content.ReadAsAsync<XElement>();
response.Dispose();
client.Dispose();
return content;
}
catch (Exception)
{
return null;
}
}
无论如何,这看起来肯定与任务、异步、后台工作程序等相关。。。是否有一种好方法可以“清除”所有其他正在运行的任务,以避免此问题
谢谢你的帮助,
Bernard.从外观上看,您的代码可以在解决第一个try块的异常事件中进入睡眠状态的一个线程之前完成,因此在它们醒来5分钟后,没有原始线程可以重新加入,从而导致AssociateWithCurrentThread的NullReferenceException添加到@kcar的答案中,我遇到了一个非常类似的问题,在代码路径上有多个等待,其中有一个方法没有被等待,如:
public async Task JsonResult BookThing(InputModel model)
{
// Do some stuff
thisIsAnAsyncMethod(Model model); // Fire and forget
return Json(null);
}
protected async Task thisIsAnAsyncMethod(Model model)
{
await oneThing();
await anotherThing();
await somethingElse();
}
这导致等待随机失败,而不让我捕获异常——因为TPL试图重新加入一个已为null的上下文,所以它在try/catch之外抛出了一个NullReferenceException
这很难诊断。在生产环境中,您不会在try/catch中看到任何内容,而在VisualStudio中,等待被安排重新加入原始上下文有点随机——这取决于TaskScheduler决定执行什么操作
如果您不想触发并忘记,最明显的答案是等待异步方法-您将收到一条编译器警告,提醒您这样做
如果您确实想启动并忘记,解决方案是显式启动一个新任务。最好的方法是。当我获得上面显示的异常和调用堆栈时,这是因为我试图使用异步执行“触发并忘记”执行,这是一个非常糟糕的主意。我切换到旋转一个新线程来满足我的需求,崩溃消失了。要做的第一件事:更改异常处理。如果出现任何错误,只返回null,而没有日志记录或提供更多诊断信息,则当前正在丢失信息。还要注意的是,您从未处理过响应。此外,您说“没有抛出异常”,但您的问题标题谈论的是NullReferenceException。哪一个?谢谢你的快速回答,约翰。正如我所说,这是一个缩短的版本,“真实”版本确实正确地处理了异常(或者我相信……)。现在,关于抛出的异常,正确的答案是“两者”…代码不会抛出异常,但是,在使用调试器对同一代码进行第二次传递之后,IntelliTrace会向我显示在前一次传递中存在“静默”异常。这更清楚吗?老实说,不太清楚。我不知道你所说的“静默”异常是什么意思,我们没有标题中提到的NullReferenceException的堆栈跟踪,我们也不知道如果没有异常逃逸,你所说的“it bombs”是什么意思。我得到了一个类似的错误和stacktrace,但没有关于异常抛出位置的指示。是否有人对如何定位有问题的代码行有任何建议?我想我以前从未使用Visual Studio错误列表中的搜索框来搜索
await
,但是如果您有许多未修复的编译器警告(咳嗽),那么只需搜索await来查找它们:)
public async Task JsonResult BookThing(InputModel model)
{
// Do some stuff
thisIsAnAsyncMethod(Model model); // Fire and forget
return Json(null);
}
protected async Task thisIsAnAsyncMethod(Model model)
{
await oneThing();
await anotherThing();
await somethingElse();
}