【问题标题】:Exception not caught in Task.Run wrapped methodTask.Run 包装方法中未捕获异常
【发布时间】:2013-08-11 18:07:38
【问题描述】:

C# 5 中异步等待集成的新手。我正在使用一些基于任务的基本方法来探索异步等待和 TPL。在下面的这个示例中,我正在调用一个超时为 5 秒的 Web 服务。如果超时到期,它应该抛出一个异常,以便我可以从该方法返回 false。但是,超时永远不会发生,或者可能会发生但任务永远不会返回。

public static Task<bool> IsConnectedAsync()
{
    return Task.Run(() =>
    {
        try
        {
            using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
            {
                return svc.PingB();
            }
        }
        catch (Exception ex)
        {
            Logger.LogException(ex.Message, ex, "IsConnectedAsync");
        }    
        return false;
    });
}

如果您能帮助如何正确处理此问题,以便在发生超时甚至更好的情况下发生异常时,任务会返回。

【问题讨论】:

    标签: c# exception-handling task-parallel-library async-await c#-5.0


    【解决方案1】:

    一般来说,如果您要包装 async 服务,则不应使用 Task.Run。由于这是一个服务引用,您应该能够直接从服务公开一个async 方法(返回Task),在这种情况下您可以使用:

    public async static Task<bool> IsConnectedAsync()
    {
        try
        {
             using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
             {
                  return await svc.PingBAsync();
             }
         }
         catch (Exception ex)
         {
             Logger.LogException(ex.Message, ex, "IsConnectedAsync");
         }    
         return false;
    }
    

    如果您必须通过Task.Run 进行包装(同样,不建议这样做,因为它通过线程池将同步代码转换为异步,这通常由顶层用户更好地处理),您可以这样做:

    public async static Task<bool> IsConnectedAsync()
    {
        try
        {
           return await Task.Run(() =>
           {
             using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
             {
                  return svc.PingB();
             }
           }
         }
         catch (Exception ex)
         {
             Logger.LogException(ex.Message, ex, "IsConnectedAsync");
             return false;
         }    
    }
    

    【讨论】:

    • 谢谢 - 不幸的是,这是一个旧的 ASMX .net 2.0 Web 服务,因此它没有可用的基于任务的异步服务。只有较旧的 Begin... End... 类型服务,所以我想我可以使用 FromAsync?不确定这是否比您上面的第二个选项更受欢迎?
    • @Neal 是的,我会将它包装在 FromAsync 中,然后使用第一种方法。
    • 第二个示例的另一个问题是您无法在异常中返回 false,因为您无法从 false 转换为 Task 我不相信。
    • 对不起,在你的第一个例子中,调用者不应该等待,所以它应该是 return svc.PingBAsync();没有等待?
    • @Neal 在第二个例子中,因为它是一个异步方法,编译器会将return false 变成Task&lt;bool&gt;。在第一个示例中,我没有让调用者进行等待,因为您有异常处理。 await 调用将使异常处理工作。 (这就是你原来的问题......)
    猜你喜欢
    • 2017-04-17
    • 1970-01-01
    • 2015-02-23
    • 2015-04-22
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    相关资源
    最近更新 更多