C# 调用HttpClient.GetAsync(url)的System.Threading.Tasks中的NullReferenceException

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

我的MVC4.0应用程序中有一个奇怪的问题。我使用RESTWeb服务(Amazon Associate)。我创建了一个方法,我在任何地方都使用它。缩略版本如下:

    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();
}