想了解异步
我已经使用了异步编码,但我并不完全理解如何使用它 – 尽管我理解这个概念以及为什么需要它。
这是我的设置:
我有一个Web API,我将从我的ASP.NET MVC应用程序调用,我的Web API将调用DocumentDB。 在代码示例中,我在向DocumentDB发送查询时看到了很多等待关键字。
如果我需要在我的MVC应用程序异步中使我的索引操作方法,我很困惑? 如果我的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(); } } // 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 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 GetCollectionAsync(string dbLink, string id) { DocumentCollection collection = client.CreateDocumentCollectionQuery(dbLink).Where(c => c.Id == id).ToArray().FirstOrDefault(); return collection; } private static async Task GetDatabaseAsync() { Database database = client.CreateDatabaseQuery().Where(db => db.Id == databaseId).ToArray().FirstOrDefault(); return database; }
如果该方法是async
并且async
方法需要返回Task
, Task
或void
,则只能在方法内使用await
,尽管返回的async
方法为事件处理程序保留了async
方法,因为它们之间抛出的exception被吞下,你无法await
它们完成或链接后续任务。
我认为您的Index
操作需要async
并返回Task
并且您的CreateEmployee
方法需要async
,并且在其中使用await
。
有关何时以及如何使用async-await
一些指导,请参阅异步编程中的最佳实践
这是我的解释
class MainClass { public static async Task 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
都是相同的代码片段。
async/await
是Task API的语法糖。 它需要你的async
方法在await
之前和之后将它分成几部分。 “之前”部分立即执行。 当await
操作完成时,“after”部分将被执行。 您可以通过Task API跟踪操作的第二部分,因为您获得了对Task的引用。
通常, async
允许将方法调用视为某种长操作,您可以通过Task API引用它并等到它完成并继续使用另一段代码。 通过ContinueWith
调用通过使用await
一般它是相同的。
在async
/ await
/ Task
概念之前,人们使用回调,但处理错误就像地狱一样简单, Task
类似于callback
的概念,除了它能够更容易地处理exception。
一般来说,所有这些Task / async / await mantra都接近promises
概念,如果你曾经使用过jQuery / JavaScript,那么这里有一个类似的概念是一个很好的问题,解释它是如何在那里完成的“ jQuery deferreds and promises – .then( )vs .done() “
编辑 :我刚刚发现.NET缺乏类似于jQuery / JavaScript中的function的实现。
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 continuation) { await task; await continuation(); } public static async Task Then ( this Task task, Func> continuation) { await task; return await continuation(); } public static async Task Then( this Task task, Func continuation) { await continuation(await task); } public static async Task Then( this Task task, Func> continuation) { return await continuation(await task); } } class MainClass { public static async Task 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 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 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 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"); } }
async await
他们很难理解。
首先,在Web API的方法中,您使用async而不等待。 我确定你会收到一些错误/警告吗?
–
async await用于在等待I / O完成时将工作线程返回给调用者。 所以,是的,你确实想在MVC和Web API方面使用它。 在继续之前请确保你理解这句话。
–
关于async / await的事情是,如果你使用它,你必须通过调用函数一直使用它,否则它没有意义(你也会得到错误/警告)。 这意味着您使用的任何库都必须支持它。 在本例中为“DocumentClient”。 按照惯例,支持它的方法将以“Async”结束,它将返回一个您可以等待的任务。
–
所以你的简短回答:从一开始就使用异步等待(你的控制器),并试着让它等待它调用的任何长操作。 如果这也是你的代码,你应该可以从那里等待…并等待那里…直到你最终调用的东西不是你的代码。 如果您可以等待那些不属于您的代码,那么您就可以了。 如果你不能,那么你不应该从一开始就使用异步等待forms。
(这没有道理)
- Autofac RegisterInstance与SingleInstance
- 如何向我未存储在数据库中的Web API响应中添加属性?
- 在Asp.net MVC中获取post数组
- 中间件中的HttpContext .NET核心保存实例
- 我应该在哪里插入我的自定义DefaultContractResolver JSON.NET?
- 使用JwtAuthForWebAPI的Web APi2身份validation不接受JWT令牌
- 使用$ expand请求控制返回的内容
- dependency injection无法与Owin自托管Web Api 2和Autofac一起使用
- WebAPI控制器inheritance和属性路由