Задание из тайм-аута синхронизации - PullRequest
5 голосов
/ 10 сентября 2011

У меня есть этот кусок кода для выполнения асинхронного 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 Ответ

8 голосов
/ 10 сентября 2011

Из документации Тайм-аут :

Свойство Timeout не влияет на асинхронные запросы, выполненные с помощью метода BeginGetResponse или BeginGetRequestStream.

Это потому, что структура заставляет вас самостоятельно управлять временем ожидания. Вы должны иметь возможность использовать пример кода здесь , за исключением передачи Task, возвращенного из вызова FromAsync, методу ThreadPool.RegisterWaitForSingleObject.


Edit:

Вам нужно поставить регистрацию на исходное задание, а не на продолжение:

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();
    });
}

Это работает для меня (если я установил очень короткое время ожидания и нажал на него, я всегда выбрал соответствующее время).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...