繁体   English   中英

使用Task.FromAsync和异步请求和异步响应进行HTTP POST

[英]Http POST using Task.FromAsync with async request and async response

我必须将异步POST发送到Web服务,并且要异步发送/检索数据。

我还需要发送请求,但最多只能等待1500毫秒以等待响应。 如果没有响应,则程序应继续运行(这是一个调用外部Web服务的服务)。 我想将这些服务调用卸载到IOCP,而不是长时间阻塞并等待它们返回。 我只想阻止1500毫秒。

这是我到目前为止的内容:

 var httpRequest = (HttpWebRequest)WebRequest.Create(@"urltoPostTo");

            httpRequest.Method = "POST";
            byte[] data = Encoding.ASCII.GetBytes("test-post");
            httpRequest.ContentLength = data.Length;
            var asyncTask = Task.Factory.FromAsync<Stream>(httpRequest.BeginGetRequestStream, httpRequest.EndGetRequestStream, httpRequest)
                .ContinueWith(response =>
                {
                    var localStream = response.Result;
                    if (localStream != null)
                    {
                        localStream.Write(data, 0, data.Length);
                        localStream.Close();
                    }
                });  //how do I do the continuation for BeginGetResponse and EndGetResponse from here?

我有两个要求,不幸的是我无法更改。

  1. 我正在使用Visual Studio 2010目标4.0
  2. 我无法使用异步BCL
  3. 我想尝试使用Task.FromAsync

这已经在实现扩展方法WebRequest.GetResponseAsync中得到了回答,该方法支持对CancellationToken的支持 ,该扩展方法具有正确处理超时和CancellationTokens的GetResponseAsync扩展方法。 当Request.Timeout过期时,该方法将调用Request.Abort ,然后将Task返回其取消状态。

进行此类编码的原因是正确处理超时是客户(您)的责任,因此您不能依靠FromAsync来处理超时到期。 也许这就是FromAsync不接受取消令牌的原因。

另一种选择是避免取消请求本身并取消继续。 您可以使用接受CancellationToken的ContinueWith重载,并调用CancellationTokenSource.CancelAfter来设置取消超时。

这将使您的代码忽略结果并继续运行,但不会断开与服务器的连接,也不会阻止后台线程处理任何潜在的昂贵结果。

您可以这样写:

var tcs=new CancellationTokenSource();
var asyncTask = Task.Factory.FromAsync<Stream>(httpRequest.BeginGetRequestStream, httpRequest.EndGetRequestStream, httpRequest)
.ContinueWith(response =>
{...},
cts.Token);  
cts.CancelAfter(1500);

请注意,在启动异步任务之后完成对CancelAfter的调用。

我宁愿在繁忙的站点中使用Reed Copsey的扩展方法,因为大量已取消但未完成的请求很容易耗尽线程池,无故消耗大量内存,并消耗与外部系统的潜在昂贵连接。

为什么不使用HttpClient?

webApiHttpClient.PostAsJsonAsync(GetFullAPI("api/Subscribe"), obj)
            .ContinueWith(res => _logger.InfoFormat("Subscribe result: {0}", res.Result.StatusCode));

试试这个方法助手。

public static Task<string> Post(string url, Encoding encoding, string content)
            {
                var httpRequest = (HttpWebRequest)WebRequest.Create(url);
                httpRequest.Method = "POST";
                byte[] data = encoding.GetBytes(content);
                httpRequest.ContentLength = data.Length;

                TaskCompletionSource<string> result = new TaskCompletionSource<string>();


                Task.Factory.FromAsync<Stream>(httpRequest.BeginGetRequestStream, httpRequest.EndGetRequestStream, httpRequest)
                   .ContinueWith(requestStreamTask =>
                   {
                       try
                       {
                           using (var localStream = requestStreamTask.Result)
                           {
                               localStream.Write(data, 0, data.Length);
                               localStream.Flush();
                           }

                           Task.Factory.FromAsync<WebResponse>(httpRequest.BeginGetResponse, httpRequest.EndGetResponse, httpRequest)
                               .ContinueWith(responseTask =>
                               {
                                   try
                                   {
                                       using (var webResponse = responseTask.Result)
                                       using (var responseStream = webResponse.GetResponseStream())
                                       using (var sr = new StreamReader(responseStream, encoding))
                                       {
                                           result.SetResult(sr.ReadToEnd());
                                       }
                                   }
                                   catch (Exception e)
                                   {
                                       result.SetException(e);
                                   }
                               }, TaskContinuationOptions.AttachedToParent);
                       }
                       catch (Exception e)
                       {
                           result.SetException(e);
                       }

                   }, TaskContinuationOptions.AttachedToParent);

                return result.Task;
            }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM