使用故障检查链接任务

时间:2013-11-27 05:38:58

标签: c# task-parallel-library task xamarin-studio

我正在使用任务来执行大量的Web服务调用,并且想要在任何时候失败都要退出。这是我目前的代码:

service.Login(usernameTextField.Text, passwordTextField.Text).ContinueWith( t => {
    if (t.IsFaulted){
        new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
    } else {
        if (t.Result)
        {
            service.GetImportantData ().ContinueWith (genericTask => {
                if (genericTask.IsFaulted){
                    new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
                }
                else {
                    service.SyncUserSpecificData().ContinueWith(projectTask => {
                        NavigationController.PopToRootViewController(true);
                    });
                }
            }, TaskScheduler.FromCurrentSynchronizationContext ());

        } else {
            new UIAlertView("Login Failed", "Please check your login and try again", null, "OK").Show();
        }
    }
    loadingOverlay.Hide();

});

它是一个Xamarin应用程序,但这并不重要,因为我只是想知道是否有更好的方法来构建它们,包括错误检查,因为它目前是回调汤。

2 个答案:

答案 0 :(得分:1)

我想说明你想要的流程是这样的:

static void DoSomething()
{
    try
    {
        bool isLoggedIn = service.Login(usernameTextField.Text, passwordTextField.Text);

        if(!isLoggedIn)
        {
            new UIAlertView("Login Failed",
                    "Please check your login and try again", null, "OK").Show();
            return;
        }

        service.GetImportantData();
        service.SyncUserSpecificData();
        NavigationController.PopToRootViewController(true);
    }
    catch
    {
        new UIAlertView("Login Failed",
                "Unable to contact server at this time", null, "OK").Show();
    }
    finally
    {
        loadingOverlay.Hide();
    }
}

在这种情况下,我会像这样异步写它:

static void DoSomething()
{
    service.Login(usernameTextField.Text, passwordTextField.Text)
        .ContinueWith(task =>
        {
            bool isLoggedIn = task.Result;

            if(!isLoggedIn)
            {
                new UIAlertView("Login Failed",
                        "Please check your login and try again", null, "OK").Show();

                // this is just a dummy task to return without error.
                return Task.FromResult(false);
            }

            return service.GetImportantData()
                .ContinueWith(task2 =>
                {
                    // do something with task2
                    task2.Wait(); // just forcing exceptions to be thrown.

                    return service.SyncUserSpecificData();
                }).Unwrap()
                .ContinueWith(task2 =>
                {
                    // task2 is the result from SyncUserSpecificData().
                    task2.Wait(); // again just forcing exceptions to be thrown.

                    NavigationController.PopToRootViewController(true);
                });
        }).Unwrap()
        .ContinueWith(task =>
        {
            new UIAlertView("Login Failed",
                    "Unable to contact server at this time", null, "OK").Show();
        }, TaskContinuationOptions.OnlyOnFaulted)
        .ContinueWith(task =>
        {
            loadingOverlay.Hide();
        });
}

这里有一些很大的不同:

首先,Unwrap()用于构成一系列延续,而不会产生大量的嵌套调用。当您从续集中返回Task时,会得到Task<Task>,而Unwrap()只返回内部Task。这不是一个神奇的子弹,但它可能会非常强大。

其次,我让异常被抛出,而不是每次都动手检查IsFaulted。当你致电Result时,如果他们在那里就会被抛出。

第三,异常通过延续自然流动,直到最后进入单一延续。

答案 1 :(得分:1)

Xamarin支持async/await关键字,您甚至可以创建支持此功能的可移植类库,如PCL and .NET NuGet Libraries are now enabled for Xamarin中所述。

这意味着您现在可以将Microsoft.Bcl.Async添加到项目中,即使在非MS平台上也可以使用async/await

使用async/await,您可以像这样重写代码:

public async Task DoStuffAsync()
{
   try
   {
       var success=await service.Login(usernameTextField.Text, passwordTextField.Text);
       if(success)
       {
           var data=await service.GetImportantData();
           await service.SyncUserSpecificData();
           NavigationController.PopToRootViewController(true);
       }
   }
   catch(WebException exc)
   {
       new UIAlertView("Login Failed", "Unable to contact server at this time", null, "OK").Show();
   }
   catch(Exception exc)
   {
       new UIAlertView("Login Failed", ex.Message, null, "OK").Show();
   }

   loadingOverlay.Hide();
}