5

我正在编写一些必须执行基本 HTTP GET 和 POST 的 C# 2.0 代码。我正在使用 System.Net.HttpWebRequest 发送这两种类型的请求,并使用 System.Net.HttpWebResponse 来接收这两种请求。我的 GET 代码如下所示:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Format("{0}?{1}",
    URLToHit,
    queryString));
request.Method = "GET";
request.Timeout = 1000; // set 1 sec. timeout
request.ProtocolVersion = HttpVersion.Version11; // use HTTP 1.1
try
{
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
}
catch(WebException e)
{
    // If I do anything except swallow the exception here, 
    // I end up in some sort of endless loop in which the same WebException 
    // keeps being re-thrown by the GetResponse method. The exception is always 
    // right (ie: in cases when I'm not connected to a network, it gives a 
    // timed out error, etc...), but it should not be re-thrown!
}

和我的 POST 代码非常相似。

当 URLToHit 返回 HTTP 状态 200 时,最后一行工作正常,但在任何其他情况下(即:非 200 HTTP 状态、无网络连接等),都会引发 System.Net.WebException(这是预期的,根据到 MSDN 文档)。但是,我的代码从未超过那条线。

当我尝试对此进行调试时,我发现我无法跳过或继续越过最后一行。当我尝试这样做时,会重新发出请求并重新抛出异常。

关于我可以做些什么来使请求只发出一次的任何想法?我从来没有在任何基于异常的代码中看到过这样的事情,而且我没有想法。我的代码的任何其他部分都不会发生类似的情况,只是处理 System.Net 功能和构造的部分。

谢谢!

(更新:围绕 GetRequest 方法添加了 try/catch)

4

5 回答 5

1

C# 中没有“不间断”异常之类的东西。要控制异常期间发生的情况,您可以使用 try-catch 块。

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Format("{0}?{1}",
    URLToHit,
    queryString));
request.Method = "GET";
request.Timeout = 1000; // set 1 sec. timeout
request.ProtocolVersion = HttpVersion.Version11; // use HTTP 1.1

try
{
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

    // Code here runs if GetResponse() was successful.
}
catch (WebException ex)
{
    // Code here runs if GetResponse() failed.
}

// Code here is always run unless another exception is thrown. 

没有“不间断异常”的原因是,如果出现异常,您的代码可能无法按照您的意图进行。例如,您希望“response”变量包含什么?你会用它做什么?try-catch 块使您可以完全控制它。

于 2009-03-16T06:15:28.547 回答
1

我已经看到了与此类似的问题,通常只有在调试器本身中,抛出异常的行才会重新运行,但这仅在异常最终未被捕获时才会发生。

你说它只在你重新抛出 catch 块时才会表现出这种行为。由于您重新抛出异常,该异常最终在哪里被捕获和处理(即由以(重新)抛出结束的捕获处理程序)?

如果答案是“无处”,那么这就是您的问题 - 在调试器下,您可能会看到异常抛出行的重新运行,并且当正常运行时,应用程序通常会由于未捕获的异常而崩溃。

于 2010-12-16T13:13:10.587 回答
1

我有完全一样的问题。这是我的制作方法:

        bool shouldRetry = true;
        do {
            try
            {
                Stream newStream = myHttpWebRequest.GetRequestStream();
                newStream.Write(byteArray, 0, byteArray.Length);
                newStream.Close();
                HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
                shouldRetry = false;
                response.Close();
                tries++;
                status = response.StatusDescription;
            }
            catch (WebException e)
            {
                tries++;
                if (tries >= 5)
                {
                    throw e;
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        } while (shouldRetry);

为了引发异常,我更改了我的主机表,因此 URI 转到我的 localhost,它没有提供任何正确的响应。

但是不断抛出异常!如果我在 Visual Studio 中调试,它会停在

throw e;

带有“未捕获的异常”通知/框。如果我按“播放”继续调试,同一行抛出异常,我无法在代码中前进。

另外,我在哪里抛出错误也没关系。我试过保存它并在 do/while、函数调用等之后抛出它。异常仍然被抛出并且一直存在。离开的唯一方法是停止调试器/退出网络服务器。(在 localhost 上,该进程占用了 100% 的 CPU),当这种状态发生在 webserver 主机上时,IIS 会在一段时间后重新启动。

Aaron,你有没有解决过这个问题?我需要那个例外,我不能“吞下”它。

更新:2010-12-16

此代码位于名为 send() 的函数中。该函数实际上是在这样的 ThreadPool.QueueUserWorkItem 中调用的。

            ThreadPool.QueueUserWorkItem((object state) =>
            {
                Thread.Sleep(1);
                try
                {
                    send();
                }
                catch (Exception e)
                {
                    throw e;
                }
            });

我目前正在尝试找出这是否与在我的情况下最终导致服务器崩溃的不间断异常有关。正如我所说..我在哪里发现异常并不重要。

更新:2010-12-16(第 2 部分)

如果我避免使用 ThreadPool.QueueUserWorkItem,我不会得到永无止境的错误。

我将继续调查.. 但也许我可以在没有 ThreadPool.QueueUserWorkItem 的情况下进行管理。

更新:2010-12-16(第 3 部分)

Thread.CurrentThread.Abort();

而不是抛出错误解决了我的问题

于 2010-12-15T17:43:40.033 回答
1

另一个注意事项,这两个代码片段之间存在差异:

catch (Exception e)
{
    throw e;
}

catch (Exception e)
{
    throw;
}

第一个示例实际上会将异常中的堆栈跟踪重置为当前堆栈位置,第二个示例将保留现有的堆栈跟踪。如果您将代码切换到第二个示例,它可能会帮助您调试问题。

于 2010-12-16T13:49:20.420 回答
0

这里有一些值得深思的地方:调试器也可以执行代码。例如,当您评估一个属性(在手表或 QuickWatch 中,甚至只是将鼠标悬停在其名称上以获取值工具提示)时,调试器将执行底层代码。并击中它在此期间遇到的任何断点。也许这就是原因?后续异常中的调用栈是什么?没有调试器也会发生这种情况吗?

于 2010-12-16T13:24:49.720 回答