【问题标题】:Async HTTPWebrequest with Timeout带超时的异步 HTTPWebrequest
【发布时间】:2012-10-02 17:25:34
【问题描述】:

环境:Windows CE / .NET Compact FrameWork 3.5。

我需要一些指导

1) 为异步 Web 请求实现超时功能。 ThreadPool::RegisterWaitForSingleObject() 不适用于 .NetCf,我有点卡住了。

2) 如何判断网络本身是否不可用? 谷歌搜索没有帮助。

注意:ThreadPool::RegisterWaitForSingleObject 不适用于 .NET Compact FrameWork。

这是我的异步实现:

void StartRequest ()
{
    try
    {
        HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://192.78.221.11/SomeFunc/excpopulatedept");
        RqstState myRequestState = new RqstState();
        myRequestState.request = myHttpWebRequest;

        // Start the asynchronous request.
        IAsyncResult result =
                    (IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);

        // Release the HttpWebResponse resource.
        myRequestState.response.Close();
    }
    catch (WebException ex)
    {
        ;
    }
    catch (Exception ex)
    {
        ;
    }
}

private void RespCallback(IAsyncResult asynchronousResult)
{
    try
    {
        //State of request is asynchronous.
        RqstState myRequestState = (RqstState)asynchronousResult.AsyncState;
        HttpWebRequest myHttpWebRequest = myRequestState.request;
        myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);

        // Read the response into a Stream object.
        Stream responseStream = myRequestState.response.GetResponseStream();
        myRequestState.streamResponse = responseStream;

        // Begin the Reading of the contents of the HTML page and print it to the console.
        IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
        return;
    }
    catch (WebException e)
    {
        Console.WriteLine("\nRespCallback Exception raised!");
        Console.WriteLine("\nMessage:{0}", e.Message);
        Console.WriteLine("\nStatus:{0}", e.Status);
    }
}

private void ReadCallBack(IAsyncResult asyncResult)
{
    try
    {
        RqstState myRequestState = (RqstState)asyncResult.AsyncState;
        Stream responseStream = myRequestState.streamResponse;
        int read = responseStream.EndRead(asyncResult);
        // Read the HTML page and then print it to the console.
        if (read > 0)
        {
            myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
            IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
            return;
        }
        else
        {
            //Console.WriteLine("\nThe contents of the Html page are : ");
            if (myRequestState.requestData.Length > 1)
            {
                string stringContent;
                stringContent = myRequestState.requestData.ToString();
                responseStream.Close();
            }
            catch (WebException e)
            {
            }
        }
    }
}

感谢您的宝贵时间。

【问题讨论】:

  • 永远不要捕获您不会以有意义的方式处理的异常。
  • @Phoenix 您可能首先要发布可编译的代码。

标签: c# .net-3.5 windows-ce


【解决方案1】:

要继续 Eric J 的评论,您在接球前有 myRequestState.response.Close()。这几乎总是会抛出异常,因为response 将为空,或者response 不会被打开。这是因为您正在异步调用BeginGetResponse,并且在调用下一行 (response.close) 时,您给它的回调可能不会被调用。您需要解决这个问题,而不是仅仅隐藏异常,因为您不知道它们发生的原因。

就超时而言,因为您要处理的事情本质上没有可配置的超时,所以您必须设置一个计时器并在超时结束时简单地关闭连接。例如

HttpWebRequest myHttpWebRequest; // ADDED
Timer timer; // ADDED

private void StartRequest()
{
        myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://192.78.221.11/SomeFunc/excpopulatedept");
        RqstState myRequestState = new RqstState();
        myRequestState.request = myHttpWebRequest;

        timer = new Timer(delegate { if (!completed) myHttpWebRequest.Abort(); }, null, waitTime, Timeout.Infinite); // ADDED
        // Start the asynchronous request.
        IAsyncResult result =
                    (IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);
}

//... 

private void ReadCallBack(IAsyncResult asyncResult)
{
    try
    {
        RqstState myRequestState = (RqstState)asyncResult.AsyncState;
        Stream responseStream = myRequestState.streamResponse;
        int read = responseStream.EndRead(asyncResult);
        // Read the HTML page and then print it to the console.
        if (read > 0)
        {
            myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
            IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, 1024, new AsyncCallback(ReadCallBack), myRequestState);
        }
        else
        {
            completed = true; // ADDED
            using(timer)  // ADDED
            {
                timer = null;
            }
            if (myRequestState.requestData.Length > 1)
            {
                string stringContent;
                stringContent = myRequestState.requestData.ToString();
                responseStream.Close();
            }
        }
    }
}

我只复制并粘贴了您的代码,因此它与您最初提供的代码一样可能编译,但应该有足够的内容让您朝着正确的方向前进。

【讨论】:

  • timer.Dispose() 将错误“对象引用未设置为对象的实例”,因为计时器为空,因为在设置计时器 = 新计时器之前调用了 BeginGetResponse。
  • 好消息@Demodave。我添加了一个 using 块,它将为我进行空值检查。但是,这只缓解了一个问题;从技术上讲,在调用ReadCallback 后启动计时器存在问题。所以,我把定时器的创建移到了BeginGetResponse之前。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
相关资源
最近更新 更多