Why waiting a task returned from async method gets blocked?

拈花ヽ惹草 提交于 2019-12-10 19:36:24

问题


I'm working on a Nancy/ASP.Net project. I've tried to use WebRequest to get data from other web service and I've implemented the request in an async function. I find a problem that when I try to wait on a task returned from the function, it gets blocked indefinitely. The simplified code looks like this..

using System.Net;
using System.Threading.Tasks;
using Nancy;

public class TestModule : NancyModule{
    public TestModule() {
        Get["/"] = p => "Hello, world";
        Get["/async/"] = p => {
            var req = WebRequest.CreateHttp("http://localhost:13254/");

//          var responseTask = req.GetResponseAsync();  // this works!
            var responseTask = getResponse(req);   // this gets blocked!
            var waitSuccess = responseTask.Wait(10000);

            return waitSuccess ? "Yeah!" : "woooh!";
        };
    }
    async Task<HttpWebResponse> getResponse(HttpWebRequest request) {
        return (HttpWebResponse) await request.GetResponseAsync();
    }
}

The code uses NancyFx but it happens as well on vanilla ASP.Net page. The service on localhost:13254 is working fine. If I use the task directly returned from request's GetResponseAsync(), the code works fine, but If I wrap it in an async method, it just gets blocked.

Does anyone have any idea what's wrong with the code? :( I can change to use synchronous version but the async function works find in other self-hosting services... so I'd like to use the same code here too if possible..


回答1:


I describe this deadlock behavior on my blog and in a recent MSDN article.

To fix this, you can either use ConfigureAwait(false) everywhere, or you can use synchronous methods. The ideal solution is to use await all the way and never use Wait or Result, but that may not be possible in your situation (it would only work if Nancy worked with async delegates, i.e., Get["/async/"] = async p => { ... };).




回答2:


In addition to solutions provided from Stephen, I resolve with just changing synchronization context at the root of Nancy route handler. Given this utility function:

using System;
using System.Threading;

namespace Utility.Async{
    static public class TPContext{
        static public T Call<T>(Func<T> handler) {
            var currentContext = SynchronizationContext.Current;
            SynchronizationContext.SetSynchronizationContext(null);
            try {
                return handler();
            }finally {
                SynchronizationContext.SetSynchronizationContext(currentContext);
            }
        } 
    }
}

Just wrap the handler with this function

        Get["/async/"] = p => TPContext.Call(() => {
            var req = WebRequest.CreateHttp("http://localhost:13254/");

            var responseTask = getResponse(req);
            var waitSuccess = responseTask.Wait(10000);

            return waitSuccess ? "Yeah!" : "woooh!";
        });

and it just works ^^a I don't think I need ASP.Net context.. and actually I hope Nancy'd make its own synchronization context since Nancy conceptually works differently from Asp.net already.



来源:https://stackoverflow.com/questions/17001761/why-waiting-a-task-returned-from-async-method-gets-blocked

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!