1

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

我还需要发送请求,但最多只等待 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. 我正在使用面向 4.0 的 Visual Studio 2010
  2. 我不能使用异步 BCL
  3. 我想尝试使用 Task.FromAsync
4

3 回答 3

1

这已经在实现扩展方法 WebRequest.GetResponseAsync 中得到解答,该方法支持 CancellationTokenGetResponseAsync扩展方法可以正确处理超时和 CancellationToken。Request.Abort当 Request.Timeout 到期时,该方法会在以取消状态返回 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 的扩展方法,因为大量已取消但未完成的请求很容易耗尽线程池,无缘无故地消耗大量内存,并消耗与外部系统的潜在昂贵连接。

于 2013-11-11T09:05:44.143 回答
0

为什么不使用 HttpClient?

webApiHttpClient.PostAsJsonAsync(GetFullAPI("api/Subscribe"), obj)
            .ContinueWith(res => _logger.InfoFormat("Subscribe result: {0}", res.Result.StatusCode));
于 2013-11-06T05:59:11.053 回答
0

试试这个方法助手。

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;
            }
于 2013-11-12T09:55:54.480 回答