http请求在嵌套的异步Task <t>方法中不起作用

时间:2015-10-06 16:35:02

标签: c# .net asynchronous httprequest

我第一次使用异步任务,我遇到了一个似乎无法解决的问题。

我有一种使用Http请求调用API的方法。

internal static async Task<HttpResponse> CallAPI(string objectname, string parameters, HttpMethod method)
    {
        HttpResponse r = new HttpResponse();

        using (r.HttpClient = new HttpClient())
        {
            r.HttpClient.BaseAddress = new Uri("https://" + Properties.Settings.Default.APIURL + "/");
            r.HttpClient.DefaultRequestHeaders.Clear();
            r.HttpClient.DefaultRequestHeaders.Add("Accept", "application/vnd+json;version=1");

            r.HttpClient.DefaultRequestHeaders.Add("Host", Properties.Settings.Default.APIURL);
            r.HttpClient.DefaultRequestHeaders.Add("Expect", "100-continue");
            r.HttpClient.DefaultRequestHeaders.Add("Connection", "Close");

            switch (method)
            {
                case HttpMethod.DELETE:
                    using (r.ResponseMessage = await r.HttpClient.DeleteAsync("api/" + objectname.ToString() + "/" + parameters))
                    {
                        var stopwatch = Stopwatch.StartNew();
                        r.responseTime = Convert.ToInt32(stopwatch.ElapsedMilliseconds);
                        r.ResponseData = await r.ResponseMessage.Content.ReadAsStringAsync();
                        return r;
                    }

                case HttpMethod.GET:
                    using (r.ResponseMessage = await r.HttpClient.GetAsync("api/" + objectname.ToString() + parameters))
                    {
                        var stopwatch = Stopwatch.StartNew();
                        r.responseTime = Convert.ToInt32(stopwatch.ElapsedMilliseconds);
                        r.ResponseData = await r.ResponseMessage.Content.ReadAsStringAsync();
                        return r;
                    }
                default: throw new Exception("No HTTP Method Found");
            }
        }

我通过按钮点击事件调用类中的delete()方法:

 protected void btnDelete_Click(object sender, EventArgs e)
    {
        Activity a = new Activity();
        a.Id = Convert.ToInt32(txtObjectId.text);
        //a.Delete(); //void method
        bool done = a.Delete().Result; //Task<bool> method
    }

如果我将delete()方法设为void,它可以正常工作并返回http响应

public async virtual void Delete()
    {
            HttpResponse r = new HttpResponse();
            r = await CallAPI(_Objectname.ToString(), _Id.ToString(), HttpMethod.DELETE);                         
    }

但如果我尝试将Delete()作为一个任务,

     public async virtual Task<bool> Delete()
    {
        try
        {
            HttpResponse r = new HttpResponse();
            r = await CallAPI(_Objectname.ToString(), _Id.ToString(), HttpMethod.DELETE);                
            return true;
        }
        catch
        {
            return false;
        }
    }

它尝试执行httpclient.deleteasync方法,应用程序只是不做任何事情。我没有得到例外,它没有冻结,它似乎似乎不再做任何事了。

我不知道是什么导致了这种行为,但我对异步编程相当新,所以我可能正在做一些我不应该做的事情: - )

1 个答案:

答案 0 :(得分:1)

如果您对使用async / await you will deadlock your program的代码执行.Result.Wait(),则必须创建事件处理程序async void,这是您唯一允许的地方使用async void

protected async void btnDelete_Click(object sender, EventArgs e)
{
    Activity a = new Activity();
    a.Id = Convert.ToInt32(txtObjectId.text);
    //await a.Delete(); //Task method
    bool done = await a.Delete(); //Task<bool> method
}

如果你最终使用的版本没有返回Task<bool> Delete()函数看起来像

public async virtual Task Delete()
{
        HttpResponse r = new HttpResponse();
        r = await CallAPI(_Objectname.ToString(), _Id.ToString(), HttpMethod.DELETE);                         
}

您不需要return声明。

此外,如果您不需要访问UI,请为每个等待调用添加.ConfigurateAwait(false),以使其不强制UI线程继续使用。

public async virtual Task Delete()
{
        HttpResponse r = new HttpResponse();
        r = await CallAPI(_Objectname.ToString(), _Id.ToString(), HttpMethod.DELETE).ConfigureAwait(false);                         
}

您也可以对CallAPI执行相同的操作,以使其更好地运行。