httpwebrequest.BeggetResponse块;如何使HTTPWebresponse异步获得的正确方法是什



我正在尝试使 HttpWebResponse对象异,以便我可以取消请求(使用 BackgroundWorker.CancellationPending flag)。但是,下方的request.BeginGetResponse线直到返回响应为止(这可能需要超过一分钟)。

Public Function myGetResponse(ByVal request As HttpWebRequest, ByRef caller As System.ComponentModel.BackgroundWorker) As HttpWebResponse
    'set a flag so that we can wait until our async getresponse finishes
    Dim waitFlag = New ManualResetEvent(False) 
    Dim recieveException As Exception = Nothing
    Dim response As HttpWebResponse = Nothing
    'I use beginGetResponse here and then wait for the result, rather than just using getResponse
    'so that this can be aborted cleanly.
    request.BeginGetResponse(Sub(result As IAsyncResult)
                                 Try 'catch all exceptions here, so they can be raised on the outer thread
                                     response = request.EndGetResponse(result)
                                 Catch e As Exception
                                     recieveException = e
                                 End Try
                                 waitFlag.Set()
                             End Sub, Nothing)

    While Not waitFlag.WaitOne(100) AndAlso Not caller.CancellationPending
        'check for cancelation every 100ms
    End While

    'if our async read from the server returned an exception, raise it here. 
    If recieveException IsNot Nothing Then
        Throw recieveException
    End If
    Return response
End Function

BeginGetResponse的MSDN文档包括段落,

BegingEtresponse方法需要一些同步设置任务才能完成(例如,DNS分辨率,代理检测和TCP套接字连接),然后该方法变得异步。结果,该方法绝不能在用户界面(UI)线程上调用,因为通常需要一些时间,通常需要几秒钟。在某些WebProxy脚本未正确配置的环境中,这可能需要60秒或更多。配置文件元素上下载时间属性的默认值是一分钟,该分钟计算大多数潜在的时间延迟。

我是在做错事,还是可能导致延迟的这些初始同步任务?如果是后者,我该如何进行此调用实际异步?

这个答案似乎暗示了一个可能的.NET错误,但是我知道我正在使用的URL有效(我本地运行Dev Server)

我正在使用VS 2010和.NET 4.0

我遇到的东西可能就是它,尽管这实际上只是黑暗中的刺伤。

您不显示如何配置HttpWebRequest对象。如果这是发布请求,则必须使用BeginGetRequestStream发送数据。作为httpwebrequest的文档。

您的应用程序无法为特定请求混合同步和异步方法。如果调用BeginGetRequestStream方法,则必须使用BeginGetResponse方法来检索响应。

MSDN文档是正确的,如果在UI线程上调用HttpWebRequest.BeginGetResponseHttpWebRequest.GetResponse,则确实有一个同步部分可以阻止UI。

因此,您需要在单独的线程上调用它。我建议使用任务并行库。Task.Factory.FromAsync可以帮助包装BeginGetResponse/EndGetResponse,然后您使用Task.Factory.StartNewTask.UnwrapTask.ContinueWith来启动在池线程上启动请求并处理其完成。这可以进一步增强以支持取消。

我对vb.net不够好,无法创建一个示例,但是在这里,它在c#(.net 4.0,vs2010)中,未经测试。将其转换为vb.net不应该是一个问题,API是相同的。

public static class WebResponseExt
{
    // convert BeginGetResponse/EndGetResponse into a Task
    static public Task<WebResponse> GetResponseTapAsync(
        this WebRequest request)
    {
        return Task.Factory.FromAsync(
             (asyncCallback, state) =>
                 request.BeginGetResponse(asyncCallback, state),
             (asyncResult) =>
                 request.EndGetResponse(asyncResult), null);
    }
    // call GetResponseTapAsync on a pool thread 
    // and unwrap the nested task
    static public Task<WebResponse> OffloadGetResponseTapAsync(
        this WebRequest request, CancellationToken token)
    {
        return Task.Factory.StartNew(
            () => request.GetResponseTapAsync(),
            token,
            TaskCreationOptions.None,
            TaskScheduler.Default).Unwrap();
    }
}
class Program
{
    void DoRequest(string url, CancellationToken token)
    {
        var request = HttpWebRequest.Create(url);
        var cancellation = token.Register(() => request.Abort());
        var task1 = request.OffloadGetResponseTapAsync(token);
        var task2 = task1.ContinueWith(
            (responseTask) =>
            {
                cancellation.Dispose();
                try
                {
                    WebResponse result = responseTask.Result;
                    // process result
                }
                catch (Exception ex)
                {
                    Debug.Print(ex.ToString());
                    // process 
                    // rethrow if needed
                    // the exception will be available as task2.Exception
                    throw; 
                }
            },
            token,
            TaskContinuationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
    }
    // ...
}

如果您决定继续使用Task的API,请考虑使用Stephen Toub的Then等任务组成模式。

相关内容

  • 没有找到相关文章

最新更新