【问题标题】:HttpClient.PostAsJsonAsync crashing without throwing exceptionHttpClient.PostAsJsonAsync 崩溃而不抛出异常
【发布时间】:2013-04-08 14:26:59
【问题描述】:

我有一个带有 WebAPI 控制器的 ASP.NET MVC 应用程序,以及一个使用这些控制器的控制台应用程序。控制台应用程序从计划任务运行,并从远程源获取数据,对其进行解析,然后在退出前将其发布到 MVC 应用程序。

这适用于几个控制器,但其中一个调用是在不引发异常的情况下使控制台应用程序崩溃。用于所有控制器的调用者代码:

    public async Task<string> Post<T>(string urlRoot, string url, T data)
    {
        var result = "";
        try
        {
            var httpClient = GetHttpClient(urlRoot);
            var response = await httpClient.PostAsJsonAsync(url, data); // Exits here
            if (response.IsSuccessStatusCode)
            {
                result = await response.Content.ReadAsAsync<string>();
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.ToString());
        }
        return result;
    }

调用await httpClient.PostAsJsonAsync(url, data)时程序退出。使用断点,既不会到达catch 块,也不会到达if 语句。然而,调用正在进行,因为使用正确的数据调用 Web API 控制器。

对于通过 API 调用传递的 T,这些程序共享相同的代码。

从输出窗口:

程序“[9640] ProgramName.vshost.exe: Managed (v4.0.30319)”已退出,代码为 0 (0x0)。

我想知道发布数据的大小是否有问题,但我没有找到任何说明大小限制的文档。

所以我的问题是:

  1. 什么可能导致控制台应用过早退出?
  2. 如何检测到这一点并防止程序退出?

【问题讨论】:

  • 您能否简要描述一下您从Main 到Post 的调用堆栈?即,您是否在任何地方使用async void,您是否在使用awaiting 所有的Tasks,等等。
  • 我在非常相似的情况下发生了这种情况。我所做的是运行Fiddler,然后我看到正在返回的Http 响应,问题是JSON.Net 无法序列化响应中使用的一些子对象。
  • 这可能对其他人有用 - 在尝试了此线程中的所有建议后,我终于删除了我的 bin 和 obj 文件夹,清理并重建了我的项目,重新启动了 Visual Studio。之后问题就消失了。 VS2015sp3 WebAPI2 MVC4

标签: c# asp.net-web-api


【解决方案1】:

一个可能的问题,就是你只是不await 执行 Post 方法。这是我正在谈论的简化版本:

    static void Main(string[] args)
    {
        Action testAction = async () =>
        {
            Console.WriteLine("In");
            await Task.Delay(100);
            Console.WriteLine("First delay");
            await Task.Delay(100);
            Console.WriteLine("Second delay");
        };
        testAction.Invoke();
        Thread.Sleep(150);
    }

testAction 将在第二个等待任务中中止,并且控制台以 0 代码退出。输出将是:

   In
   First delay
   Press any key to continue . . .

就我而言,我会在 Main 方法的末尾添加 Console.ReadKey() 调用。在你的情况下,可能需要一些不同的东西

【讨论】:

    【解决方案2】:

    请看一下这个问题,它列举了一些你需要处理的异常:

    .NET Global exception handler in console application

    Application.ThreadException += MYThreadHandler;
    
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    

    对于任务异常也可以考虑这种方法:

    static void Main(string[] args)
    {
        Task<int> task = new Task<int>(Test);
        task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
        task.Start();
        Console.ReadLine();
    }
    
    static int Test()
    {
        throw new Exception();
    }
    
    static void ExceptionHandler(Task<int> task)
    {
        var exception = task.Exception;
        Console.WriteLine(exception);
    }
    

    您可以在此问题的其中一个答案中找到更多详细信息:

    catch exception that is thrown in different thread

    【讨论】:

      【解决方案3】:
      1. 一旦你点击 await 控制将返回给 Post 的调用者。

      2. 不要在 post 方法中等待,而是从返回的任务中使用 ContinueWith,例如:Task continuation on UI thread 或等待返回的任务:http://msdn.microsoft.com/en-gb/library/dd537610.aspx

      【讨论】:

        【解决方案4】:

        我建议测试一下 JSON.Net 序列化器是否能够序列化您的类型。

        【讨论】:

        • @harriyott 如果您运行 fiddler,您是否看到对服务器的请求启动。是成功还是失败?
        • 它到达服务器 - 控制器中的断点被命中,并且正确的数据正在通过。
        • 尝试开启首次机会异常,看看是否有帮助
        【解决方案5】:

        "exited with code 0" 表示程序正常退出。因此,它可能是Post&lt;T&gt; 的调用者或什至以上调用者确定是时候结束程序了。如果您熟悉 WinDbg 等调试工具,可以在 ntdll 函数处设置原生断点以进一步诊断案例,但通常只需要查看您的代码库即可。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-09-30
          • 1970-01-01
          • 2013-07-15
          • 1970-01-01
          相关资源
          最近更新 更多