【问题标题】:Catch exception in async Task在异步任务中捕获异常
【发布时间】:2018-09-05 10:20:37
【问题描述】:

我正在使用 C#(控制台应用程序)。

在我的程序中,我必须联系 httpClient。首先,我检查客户端是否使用GetAsync 进行响应。所以我的请求方法是异步的,使我的任务异步。

当客户端没有响应(或其他原因)时,它会抛出异常但我无法捕获它。

我添加了ContinueWith,但它不起作用。通过一个断点,我看到在我的任务开始时到达了这段代码,因此异常始终为空。

我该如何解决这个问题?

这是我的代码:

static void Run()
{
    String urlRequest = "";
    CancellationTokenSource cts = new CancellationTokenSource();
    CancellationToken ct = cts.Token;

    Console.WriteLine($"Program running, press a key to stop");
    try
    {
        Task task = Task.Factory.StartNew(async () =>
        {
            using (HttpClientHandler handler = new HttpClientHandler { Credentials = new NetworkCredential("user", "pass") })
            {
                HttpClient client = new HttpClient(handler);
                client.BaseAddress = new Uri(urlRequest);
                client.DefaultRequestHeaders.Accept.Clear();
                bool serviceAvailable = await CheckService(client);
                if (serviceAvailable)
                {
                    bool doLoop = true;
                    while (doLoop)
                    {
                        // Do something

                        Thread.Sleep(100);
                        if (ct.IsCancellationRequested)
                        {
                            Console.WriteLine("\r\ntask cancelled");
                            break;
                        }
                    }
                }
                else
                {
                    throw new HttpRequestException($"Unable to contact service at {urlRequest}");
                }
            }

        }, ct).ContinueWith(tsk =>
        {
            if (tsk.Exception != null)
                throw tsk.Exception;
        });

        Console.ReadKey();
        cts.Cancel();
        Thread.Sleep(1000);
    }
    catch (Exception e)
    {
        Log(e);
    }
}

static async Task<bool> CheckClient(HttpClient client)
{
    Console.WriteLine("Check service Call ...");
    HttpResponseMessage response = await client.GetAsync("CheckService");
    if (response.IsSuccessStatusCode)
    {
        return true;
    }

    return false;
}

【问题讨论】:

  • CheckClient 实际上告诉你的是,不久前,服务在其CheckService 端点响应。它不会告诉您该服务是否可用于任何其他目的,或者您是否现在运行相同的检查,您会得到相同的答案。考虑到这些限制,知道这一点真的有用吗?特别是,如果//Do something 使用该服务,它不会告诉你即使一次也能成功。
  • 您应该使用 Task.Run 而不是任务工厂,因为显然 StartNew 不理解异步委托。更多细节在这里:blog.stephencleary.com/2013/08/startnew-is-dangerous.html

标签: c# multithreading task


【解决方案1】:

您既不等待也不观察任务的结果。假设您在 .Net 4.5 或更高版本上运行此程序,则存在异常但不会引起注意。

所以,首先,您应该.Wait() 让您的任务完成,以便调用代码有机会观察到异常。

一般来说,您应该避免使用Task.Factory.StartNew(),而更喜欢Task.Run() - 请参阅Stephen Toub's explanation why。但是,如果您出于某种原因更喜欢使用Task.Factory.StartNew,那么您还必须首先.Unwrap() 原始任务才能获得您想要结果的实际任务。 (请注意.Unrwap() 是可用于Task&lt;Task&gt; 但不适用于Task 的扩展方法,因此请输入相应的原始变量;即使用var task = Task.Factory.StartNew(...)

【讨论】:

  • 我用Task.Run 替换了我的Task.Factory.StartNew() ,它运行良好。谢谢
【解决方案2】:

ContinueWith 将在任务完成时执行,无论成功与否。

如果成功,您在 ContinueWith 中的tsk.Exception 将为空。

你可以试试:

.StartNew(...)
.ContinueWith(tsk =>
        {
            //thrown
        },TaskContinuationOptions.OnlyOnFaulted);

【讨论】:

  • 我已经尝试过了,但现在永远无法到达if/throw
  • 这意味着没有例外。您可以尝试通过在 CheckClient 中抛出异常
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
  • 2011-08-12
相关资源
最近更新 更多