9

我已经使用了一点异步编码,但我并不完全理解如何使用它——尽管我理解这个概念以及我为什么需要它。

这是我的设置:

我有一个 Web API,我将从我的 ASP.NET MVC 应用程序调用,我的 Web API 将调用 DocumentDB。在代码示例中,我在向 DocumentDB 发送查询时看到了很多 await 关键字。

如果我需要在我的 MVC 应用程序中使我的 Index 操作方法异步,我会感到困惑吗?如果我的 Web API 中的 CreateEmployee() 方法应该是异步的,我也很困惑?

在这种情况下使用异步的正确方法是什么?

这是我的代码(此代码当前给我错误,因为我的 MVC 操作方法不是异步的)---- ASP.NET MVC 应用程序代码----

public ActionResult Index()
{

   Employee emp = new Employee();
   emp.FirstName = "John";
   emp.LastName = "Doe";
   emp.Gender = "M";
   emp.Ssn = "123-45-6789";

   using (var client = new HttpClient())
   {
      client.BaseAddress = new Uri("http://myWebApi.com");
      client.DefaultRequestHeaders.Accept.Clear();
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

      HttpResponseMessage response = await client.PostAsJsonAsync("hr/create/newemployee", emp);
      if (response.IsSuccessStatusCode)
      {
         emp = await response.Content.ReadAsAsync<Employee>();
      }
   }

   // Display employee info
   return View(emp);
}

---- Web API 代码 ----

private static readonly string endPointUrl = ConfigurationManager.AppSettings["EndPointUrl"];
private static readonly string authorizationKey = ConfigurationManager.AppSettings["AuthorizationKey"];
private static readonly string databaseId = ConfigurationManager.AppSettings["DatabaseId"];
private static DocumentClient client;

public static async Task<Employee> CreateEmployee(Employee emp)
{
   try
   {
      //Create a Document client
      using (client = new DocumentClient(new Uri(endPointUrl), authorizationKey))
      {
         //Get the database
         var database = await GetDatabaseAsync();

         //Get the Document Collection
         var collection = await GetCollectionAsync(database.SelfLink, "Employees");

         await client.CreateDocumentAsync(collection.SelfLink, emp);

         // Further process employee
       }
    }
    catch
    {
       // Handle error
    }

    return employee;
}

private static async Task<DocumentCollection> GetCollectionAsync(string dbLink, string id)
{
   DocumentCollection collection = client.CreateDocumentCollectionQuery(dbLink).Where(c => c.Id == id).ToArray().FirstOrDefault();

   return collection;
}

private static async Task<Database> GetDatabaseAsync()
{
   Database database = client.CreateDatabaseQuery().Where(db => db.Id == databaseId).ToArray().FirstOrDefault();

   return database;
}
4

3 回答 3

8

这是我的解释

class MainClass
{
    public static async Task<String> AsyncMethod(int delay) {

        await Task.Delay (TimeSpan.FromSeconds(delay));

        return "The method has finished it's execution after waiting for " + delay + " seconds";
    }

    public static async Task Approach1(int delay)
    {
        var response = await AsyncMethod (delay); // await just unwraps Task's result

        Console.WriteLine (response);
    }

    public static Task Approach2(int delay)
    {
        return AsyncMethod(delay).ContinueWith(message => Console.WriteLine(message)); // you could do the same with 
    }

    public static void Main (string[] args)
    {
        var operation1 = Approach1 (3);
        var operation2 = Approach2 (5);

        Task.WaitAll (operation1, operation2);

        Console.WriteLine("All operations are completed")
    }
}

最终两者Approach1都是Approach2相同的代码。

是围绕任务 API的async/await语法糖。它需要您的async方法将其拆分为 beforeawait和 after部分await。“之前”部分立即执行。await操作完成后将执行“之后”部分。由于您获得了对任务的引用,因此您可以通过任务 API 跟踪操作的第二部分。

通常async允许将方法调用视为某种长操作,您可以通过 Task API 引用它并等待它完成并继续执行另一段代码。无论是通过ContinueWith调用还是通过使用await,通常都是一样的。

async//概念之前人们都在使用回调,但是处理错误简直是天方夜谭,await类似于一个概念,只是它能够更轻松地处理异常。TaskTaskcallback

一般来说,所有这些 Task/async/await 口头禅都接近于promises如果你使用过 jQuery/JavaScript 的概念,有一个类似的概念这里有一个很好的问题,解释了它是如何在那里完成的“ jQuery deferreds and promises - .then()与 .done() "


编辑:我刚刚发现 .NET 缺乏then类似于 jQuery/JavaScript 中的功能实现。

ContinueWith和之间的区别在于Then可以Then组合任务,并顺序执行它们,而ContinueWith不能,它只能并行启动任务,但可以通过 await 构造轻松实现。这是我更新的代码,其中包含整个 shebang:

static class Extensions
{
    // Implementation to jQuery-like `then` function in .NET
    // According to: http://blogs.msdn.com/b/pfxteam/archive/2012/08/15/implementing-then-with-await.aspx
    // Further reading: http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx
    public static async Task Then(this Task task, Func<Task> continuation) 
    { 
        await task; 
        await continuation(); 
    } 

    public static async Task<TNewResult> Then<TNewResult>( 
        this Task task, Func<Task<TNewResult>> continuation) 
    { 
        await task; 
        return await continuation(); 
    } 

    public static async Task Then<TResult>( 
        this Task<TResult> task, Func<TResult,Task> continuation) 
    { 
        await continuation(await task); 
    } 

    public static async Task<TNewResult> Then<TResult, TNewResult>( 
        this Task<TResult> task, Func<TResult, Task<TNewResult>> continuation) 
    { 
        return await continuation(await task); 
    }
}

class MainClass
{
    public static async Task<String> AsyncMethod1(int delay) {

        await Task.Delay (TimeSpan.FromSeconds(delay));

        return "The method has finished it's execution after waiting for " + delay + " seconds";
    }

    public static Task<String> AsyncMethod2(int delay)
    {
        return Task.Delay (TimeSpan.FromSeconds (delay)).ContinueWith ((x) => "The method has finished it's execution after waiting for " + delay + " seconds");
    }

    public static async Task<String> Approach1(int delay)
    {
        var response = await AsyncMethod1 (delay); // await just unwraps Task's result

        return "Here is the result of AsyncMethod1 operation: '" + response + "'";
    }

    public static Task<String> Approach2(int delay)
    {
        return AsyncMethod2(delay).ContinueWith(message => "Here is the result of AsyncMethod2 operation: '" + message.Result + "'");
    }

    public static void Main (string[] args)
    {
        // You have long running operations that doesn't block current thread
        var operation1 = Approach1 (3); // So as soon as the code hits "await" the method will exit and you will have a "operation1" assigned with a task that finishes as soon as delay is finished
        var operation2 = Approach2 (5); // The same way you initiate the second long-running operation. The method also returns as soon as it hits "await"

        // You can create chains of operations:
        var operation3 = operation1.ContinueWith(operation1Task=>Console.WriteLine("Operation 3 has received the following input from operation 1: '" + operation1Task.Result + "'"));
        var operation4 = operation2.ContinueWith(operation2Task=>Console.WriteLine("Operation 4 has received the following input from operation 2: '" + operation2Task.Result + "'"));

        var operation5 = Task.WhenAll (operation3, operation4)
            .Then(()=>Task.Delay (TimeSpan.FromSeconds (7)))
            .ContinueWith((task)=>Console.WriteLine("After operation3 and 4 have finished, I've waited for additional seven seconds, then retuned this message"));

        Task.WaitAll (operation1, operation2); // This call will block current thread;

        operation3.Wait (); // This call will block current thread;
        operation4.Wait (); // This call will block current thread;
        operation5.Wait (); // This call will block current thread;

        Console.WriteLine ("All operations are completed");
    }
}
于 2014-11-25T01:06:31.010 回答
7

await如果该方法是async并且async方法需要返回,则您只能在该方法内部使用TaskTask<T>或者void尽管void返回async方法是为事件处理程序保留的,因为其中抛出的异常被吞没并且您无法await完成或链接后续任务。

我认为您的Index操作必须是async并返回 aTask<ActionResult>并且您的CreateEmployee方法需要与async它在其中使用的一样await好。

有关何时以及如何使用的一些指南,请参阅异步编程中的最佳实践async-await

于 2014-11-25T00:59:36.363 回答
1
async await

他们很难理解。

首先,在您的 Web API 方法中,您使用的是没有等待的异步。我确定您在那里收到了一些错误/警告,对吗?

--

async await 用于在等待 I/O 完成时将工作线程返回给调用者。所以,是的,您确实希望在 MVC 和 Web API 端都使用它。在继续之前,请确保您理解这句话。

--

关于 async / await 的事情是,如果你使用它,你必须通过调用函数一直使用它,否则它没有意义(你也会得到错误/警告)。这意味着您使用的任何库都必须支持它。在本例中为“DocumentClient”。按照惯例,支持它的方法将以“Async”结尾,它会返回一个您可以等待的任务。

--

所以你的简短回答:从一开始就使用异步等待(你的控制器),并尝试让它等待它调用的任何长时间操作。如果这也是您的代码,您应该能够从那里等待......并从那里等待......直到您最终调用不是您的代码的东西。如果您可以等待不属于您的代码,那么您已经准备就绪。如果你不能,那么你不应该从一开始就使用 async await。

(这毫无意义)

于 2014-11-25T00:53:43.753 回答