使用异步请求超时回调回调

2023-09-04 23:28:16 作者:诶,妥了妥了。

我问过这个问题,但我会完成与提出的解决方案的问题,并做出另一个问题。

我使用这个类进行异步的WebRequest < /一>:

 类HttpSocket
{
    公共静态无效MakeRequest(URI URI,动作&LT; RequestCallbackState&GT; responseCallback)
    {
        WebRequest的请求= WebRequest.Create(URI);
        request.Proxy = NULL;

        任务&LT; WebResponse的&GT; AsyncTask的= Task.Factory.FromAsync&LT; WebResponse的&GT;(request.BeginGetResponse,request.EndGetResponse,NULL);
        ThreadPool.RegisterWaitForSingleObject((AsyncTask的为IAsyncResult的).AsyncWaitHandle,新WaitOrTimerCallback(TimeoutCallback)的要求,1000年,真正的);
        asyncTask.ContinueWith(任务=&GT;
            {
                WebResponse的响应= task.Result;
                流responseStream = response.GetResponseStream();
                responseCallback(新RequestCallbackState(response.GetResponseStream()));
                responseStream.Close();
                response.Close();
            });
    }

    私有静态无效TimeoutCallback(对象状态,布尔TIMEDOUT)
    {
        Console.WriteLine(超时:+ TIMEDOUT);
        如果(TIMEDOUT)
        {
            Console.WriteLine(超时);
            WebRequest的要求=(WebRequest的)状态;
            如果(状态!= NULL)
            {
                request.Abort();
            }
        }
    }
}
 

和我测试的类与此code:

 类节目
{
    静态无效的主要(字串[] args)
    {
        //发出请求到一个不存在的域。
        HttpSocket.MakeRequest(新的URI(HTTP://www.google.comhklhlñ),callbackState =&GT;
            {
                如果(callbackState.Exception!= NULL)
                    扔callbackState.Exception;
                Console.WriteLine(GetResponseText(callbackState.ResponseStream));
            });
        Thread.sleep代码(100000);
    }

    公共静态字符串GetResponseText(流responseStream)
    {
        使用(VAR读卡器=新的StreamReader(responseStream))
        {
            返回reader.ReadToEnd();
        }
    }
}
 

一旦执行,回调马上达到,显示超时:假,有没有更多的罚球,让超时工作不

登录网站提示 请求数据成功 但回调方法出错

这是在原来的线程提出了一个解决方案,但是,因为你可以看到中,code为他工作。

我在做什么错了?

编辑:使用的code。其他类:

 类RequestCallbackState
{
    公共流ResponseStream {获得;私定; }
    公共异常异常{获得;私定; }

    公共RequestCallbackState(流responseStream)
    {
        ResponseStream = responseStream;
    }

    公共RequestCallbackState(例外的例外)
    {
        异常=例外,
    }
}

类RequestState
{
    公共字节[] RequestBytes {获得;组; }
    公众的WebRequest请求{获得;组; }
    公益行动&LT; RequestCallbackState&GT; ResponseCallback {获得;组; }
}
 

解决方案

此方法效果。我会建议切换这明确地处理异常情况(包括你超时,但也很糟糕域名等)略有不同。在这种情况下,我这个分裂成一个单独的延续。

此外,为了使这个非常明确,我已经短的超时时间,把一个真正的,但是进展缓慢域,因为增加了一个明确的暂停状态,你可以看到,以及:

 使用系统;
使用System.IO;
使用System.Net;
使用的System.Threading;
使用System.Threading.Tasks;

类HttpSocket
{
    私人const int的TimeoutLength = 100;

    公共静态无效MakeRequest(URI URI,动作&LT; RequestCallbackState&GT; responseCallback)
    {
        WebRequest的请求= WebRequest.Create(URI);
        request.Proxy = NULL;

        任务&LT; WebResponse的&GT; AsyncTask的= Task.Factory.FromAsync&LT; WebResponse的&GT;(request.BeginGetResponse,request.EndGetResponse,NULL);
        ThreadPool.RegisterWaitForSingleObject((AsyncTask的为IAsyncResult的).AsyncWaitHandle,新WaitOrTimerCallback(TimeoutCallback),要求TimeoutLength,真正的);
        asyncTask.ContinueWith(任务=&GT;
            {
                WebResponse的响应= task.Result;
                流responseStream = response.GetResponseStream();
                responseCallback(新RequestCallbackState(response.GetResponseStream()));
                responseStream.Close();
                response.Close();
            },TaskContinuationOptions.NotOnFaulted);
        //处理错误
        asyncTask.ContinueWith(任务=&GT;
            {
                VAR例外= task.Exception;
                VAR webException = exception.InnerException;

                //跟踪您是否取消或不...给你...
                responseCallback(新RequestCallbackState(exception.InnerException,webException.Message.Contains(请求被取消。)));
            },TaskContinuationOptions.OnlyOnFaulted);
    }

    私有静态无效TimeoutCallback(对象状态,布尔TIMEDOUT)
    {
        Console.WriteLine(超时:+ TIMEDOUT);
        如果(TIMEDOUT)
        {
            Console.WriteLine(超时);
            WebRequest的要求=(WebRequest的)状态;
            如果(状态!= NULL)
            {
                request.Abort();
            }
        }
    }
}

类RequestCallbackState
{
    公共流ResponseStream {获得;私定; }
    公共异常异常{获得;私定; }

    公共BOOL请求超时{获得;私定; }

    公共RequestCallbackState(流responseStream)
    {
        ResponseStream = responseStream;
    }

    公共RequestCallbackState(例外的例外,布尔TIMEDOUT = FALSE)
    {
        异常=例外,
        请求超时= TIMEDOUT;
    }
}

类RequestState
{
    公共字节[] RequestBytes {获得;组; }
    公众的WebRequest请求{获得;组; }
    公益行动&LT; RequestCallbackState&GT; ResponseCallback {获得;组; }
}

类节目
{
    静态无效的主要(字串[] args)
    {
        //发出请求到一个不存在的域。
        HttpSocket.MakeRequest(新的URI(http://www.tanzaniatouristboard.com/),callbackState =&GT;
            {
                如果(callbackState.RequestTimedOut)
                {
                    Console.WriteLine(暂停!);
                }
                否则,如果(callbackState.Exception!= NULL)
                    扔callbackState.Exception;
                其他
                    Console.WriteLine(GetResponseText(callbackState.ResponseStream));
            });
        Thread.sleep代码(100000);
    }

    公共静态字符串GetResponseText(流responseStream)
    {
        使用(VAR读卡器=新的StreamReader(responseStream))
        {
            返回reader.ReadToEnd();
        }
    }
}
 

这将运行,并适当地显示超时。

I asked this question before but I'm going to complete the question with a solution proposed and make another question.

I'm using this class to make an async WebRequest:

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

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

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

And i'm testing the class with this code:

class Program
{
    static void Main(string[] args)
    {
        // Making a request to a nonexistent domain.
        HttpSocket.MakeRequest(new Uri("http://www.google.comhklhlñ"), callbackState =>
            {
                if (callbackState.Exception != null)
                    throw callbackState.Exception;
                Console.WriteLine(GetResponseText(callbackState.ResponseStream));
            });
        Thread.Sleep(100000);
    }

    public static string GetResponseText(Stream responseStream)
    {
        using (var reader = new StreamReader(responseStream))
        {
            return reader.ReadToEnd();
        }
    }
}

Once executed, the callback is reached immediately, showing "Timeout: false" and there aren't more throws, so the timeout isn't working.

This is a solution proposed in the original thread but, as you could see, the code works for him.

What I'm doing wrong?

EDIT: Other classes used by the code:

class RequestCallbackState
{
    public Stream ResponseStream { get; private set; }
    public Exception Exception { get; private set; }

    public RequestCallbackState(Stream responseStream)
    {
        ResponseStream = responseStream;
    }

    public RequestCallbackState(Exception exception)
    {
        Exception = exception;
    }
}

class RequestState
{
    public byte[] RequestBytes { get; set; }
    public WebRequest Request { get; set; }
    public Action<RequestCallbackState> ResponseCallback { get; set; }
}

解决方案

This approach works. I would recommend switching this to explicitly handle exceptions (including your timeout, but also bad domain names, etc) slightly differently. In this case, I've split this into a separate continuation.

In addition, in order to make this very explicit, I've shorted the timeout time, put a "real" but slow domain in, as well as added an explicit timeout state you can see:

using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

class HttpSocket
{
    private const int TimeoutLength = 100;

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

        Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
        ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), request, TimeoutLength, true);
        asyncTask.ContinueWith(task =>
            {
                WebResponse response = task.Result;
                Stream responseStream = response.GetResponseStream();
                responseCallback(new RequestCallbackState(response.GetResponseStream()));
                responseStream.Close();
                response.Close();
            }, TaskContinuationOptions.NotOnFaulted);
        // Handle errors
        asyncTask.ContinueWith(task =>
            {
                var exception = task.Exception;
                var webException = exception.InnerException;

                // Track whether you cancelled or not... up to you...
                responseCallback(new RequestCallbackState(exception.InnerException, webException.Message.Contains("The request was canceled.")));
            }, TaskContinuationOptions.OnlyOnFaulted);
    }

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

class RequestCallbackState
{
    public Stream ResponseStream { get; private set; }
    public Exception Exception { get; private set; }

    public bool RequestTimedOut { get; private set; }

    public RequestCallbackState(Stream responseStream)
    {
        ResponseStream = responseStream;
    }

    public RequestCallbackState(Exception exception, bool timedOut = false)
    {
        Exception = exception;
        RequestTimedOut = timedOut;
    }
}

class RequestState
{
    public byte[] RequestBytes { get; set; }
    public WebRequest Request { get; set; }
    public Action<RequestCallbackState> ResponseCallback { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // Making a request to a nonexistent domain.
        HttpSocket.MakeRequest(new Uri("http://www.tanzaniatouristboard.com/"), callbackState =>
            {
                if (callbackState.RequestTimedOut)
                {
                    Console.WriteLine("Timed out!");
                }
                else if (callbackState.Exception != null)
                    throw callbackState.Exception;
                else
                    Console.WriteLine(GetResponseText(callbackState.ResponseStream));
            });
        Thread.Sleep(100000);
    }

    public static string GetResponseText(Stream responseStream)
    {
        using (var reader = new StreamReader(responseStream))
        {
            return reader.ReadToEnd();
        }
    }
}

This will run, and show a timeout appropriately.

 
精彩推荐
图片推荐