来自异常超时的任务

时间:2011-09-10 00:17:39

标签: c# asynchronous

我有这段代码来发出异步HTTP请求:

    public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback)
    {
        WebRequest request = WebRequest.Create(uri);
        request.Proxy = null;

        Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null).ContinueWith(task =>
            {
                WebResponse response = task.Result;
                Stream responseStream = response.GetResponseStream();
                responseCallback(new RequestCallbackState(response.GetResponseStream()));
                responseStream.Close();
                response.Close();
            });
    }

它可以工作,但我需要设置一个请求超时。我试图使用request.Timeout但似乎没有做任何事情。有没有办法在此代码中设置任务超时?

编辑添加新的超时回调。 新代码:

    public static void MakeRequest(Uri uri, Action<RequestCallbackState> responseCallback)
    {
        WebRequest request = WebRequest.Create(uri);
        request.Proxy = null;

        IAsyncResult t = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null).ContinueWith(task =>
            {
                WebResponse response = task.Result;
                Stream responseStream = response.GetResponseStream();
                responseCallback(new RequestCallbackState(response.GetResponseStream()));
                responseStream.Close();
                response.Close();
            });
        ThreadPool.RegisterWaitForSingleObject(t.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, 1000, true);
    }

    private static void TimeoutCallback(object state, bool timedOut)
    {
        if (timedOut)
        {
            Console.WriteLine("Timeout");
            WebRequest request = (WebRequest)state;
            if (state != null)
            {
                request.Abort();
            }
        }
    }

测试:

HttpSocket.MakeRequest(new Uri("http://www.google.comhklhlñ"), callbackState =>
    {
        if (callbackState.Exception != null)
            throw callbackState.Exception;
        Console.WriteLine(GetResponseText(callbackState.ResponseStream));
    });
Thread.Sleep(10000);

1 个答案:

答案 0 :(得分:8)

来自Timeout documentation

  

Timeout属性对使用BeginGetResponse或BeginGetRequestStream方法进行的异步请求没有影响。

这是因为框架强迫您自己处理超时。您应该可以使用example code here,除了将Task调用返回的FromAsync传递给ThreadPool.RegisterWaitForSingleObject方法。


编辑:

您需要将注册放在原始任务上,而不是继续:

public static void MakeRequest(Uri uri, Action<Stream> responseCallback)
{
    WebRequest request = WebRequest.Create(uri);
    request.Proxy = null;
    const int TimeoutPeriod = 1000;

    Task<WebResponse> t = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    ThreadPool.RegisterWaitForSingleObject((t as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, TimeoutPeriod, true);
    t.ContinueWith(task =>
    {
        WebResponse response = task.Result;
        Stream responseStream = response.GetResponseStream();
        responseCallback(response.GetResponseStream());
        responseStream.Close();
        response.Close();
    });
}

这适用于我(如果我将超时持续时间设置得非常短,并点击这个,我总是适当地超时)。