我必须向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?
我有一些要求,遗憾的是我无法改变。
答案 0 :(得分:1)
Implementing extension method WebRequest.GetResponseAsync with support for CancellationToken已经使用GetResponseAsync
扩展方法正确处理了超时和CancellationTokens。当Request.Timeout到期时,该方法在将Task返回到已取消状态之前调用Request.Abort
。
这种涉及编码的原因是客户(你的)有责任正确处理超时,因此你不能依赖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在繁忙站点中的扩展方法,因为大量已取消但未完成的请求很容易耗尽线程池,无理由消耗大量内存并消耗可能昂贵的外部系统连接。
答案 1 :(得分:0)
为什么不使用HttpClient?
webApiHttpClient.PostAsJsonAsync(GetFullAPI("api/Subscribe"), obj)
.ContinueWith(res => _logger.InfoFormat("Subscribe result: {0}", res.Result.StatusCode));
答案 2 :(得分: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;
}