调试异步等待控制器操作

时间:2016-03-16 04:48:44

标签: c# asp.net-web-api visual-studio-2015 async-await

我已经在ApiController中表达了一种简单的async方法(我认为):

public class CommentsController : ApiController
{
    private static readonly IList<CommentModel> Comments;

    static CommentsController()
    {
        // Note: Removed to abbreviate - populate comments manually here.
    }

    [ResponseType(typeof (IList<CommentModel>))]
    [HttpGet]
    public async Task<IHttpActionResult> GetAllComments()
    {
        return await Task.Factory.StartNew(() =>
        {
            Thread.Sleep(10000); // Breakpoint #1
            return Ok(Comments); // Breakpoint #2
        });

        // Breakpoint #3
    }
}

请注意我上面提到的断点。

我期望发生的事情是在我点击继续时排在第一位,让线程等待但是流程在此阶段继续通过#3。

然后当睡眠结束时,再次继续并在#2处休息。

然而,在调试过程中它似乎是同步的。

我的问题首先是这是真正的异步,如何调试它来验证,或者使用单元测试?

3 个答案:

答案 0 :(得分:3)

  

然而,在调试过程中它似乎是同步的。

它是串行(非同步),因为await关键字告诉方法在该操作完成之前不会继续。调试器将以串行方式逐步执行异步方法,这可以使它们看起来是同步的;这比使调试器跳转到不相关的代码然后稍后再跳回来更自然。

  

我的问题首先是这是真正的异步

这是假的异步。在现实世界的代码中,您永远不会使用Task.Factory.StarNew

此外,对于ASP.NET应用程序,您应该避免将工作发送到线程池(StartNewTask.Run等)。相反,您应该调用自然异步API。

  

如何调试它以验证或以其他方式进行单元测试?

您可以调用该方法,验证任务是否尚未完成,然后等待它。请注意,为避免竞争条件,您应该删除控制器正在使用的任何异步服务。

答案 1 :(得分:2)

断点3 永远不会被击中,也不应该被击中。

Task开头的Task.Factory.StartNew将以异步方式运行 但是await基本上等待Task在继续当前方法之前完成执行,并将执行返回给调用者。因此,它会为给定的Task添加延续 由于您返回Task的结果,断点3 将永远不会执行。

如果你想在Task之后执行 Breakpoint 3 ,你基本上有两个选择:

您可以添加续集:

    return await Task.Factory.StartNew(() =>
    {
        Thread.Sleep(10000); // Breakpoint #1
        return Ok(Comments); // Breakpoint #2
    }).ContinueWith((Task<IHttpActionResult> t) => 
    {
        //t.Result contains the result of the previous Task
        return t.Result; // Breakpoint #3
    });

或(更简单),使用临时值和await

    var temp = await Task.Factory.StartNew(() =>
    {
        Thread.Sleep(10000); // Breakpoint #1
        return Ok(Comments); // Breakpoint #2
    });

    // Breakpoint #3
    return temp;

要在不等待执行完成的情况下调用async方法,请忽略await。所以,如果你想并行执行GetAllComments 5次,你可以这样做:

for(int i = 0; i < 5; i++)
    GetAllComments();

答案 2 :(得分:1)

Breakpoint#3将如何被击中?你在等待之前得到了回报。

所以,会发生的事情是await会产生一个状态机,并且在完成你的线程后只会返回该值。