使用HttpWebResponse重新连接到Background Worker中的网站?

时间:2015-02-05 14:26:33

标签: c# .net xml

我现在面临的问题是微不足道,因为我使用C sharp中的Background Worker每天24小时都与网站建立联系。主要问题是数据提供者(网站)偶尔会断开它的连接,我的后台工作人员只是无所事事地闲着。一旦网站连接断开,我需要再次重新建立连接。目前这似乎很难。

我正在考虑创建一个无限循环来检查单独线程中的HttpWebResponse。但是,这会使事情变得更加复杂,因为将变量从一个线程传递到另一个线程并不能简化这个问题。

我正在寻找的是使用Background Worker类的一些原生解决方案。我想到的一件事是我可以检查HttpWebResponse以了解何时重新连接。这样的东西放在BackgroundWorker_DoWork函数中:

if (Response.StatusCode != System.Net.HttpStatusCode.OK)
{
   //reconnect
}

但是,我是Background Worker类的新手,我无法在后台工作程序代码中找到无限循环的位置。

我假设"做什么" BackgroundWorker_DoWork函数中的循环可能是一个地方,但是当我在代码中打印这样的东西时,它不会在我的控制台窗口上打印任何内容。

Console.WriteLine("Connection Lost. Current Status Code " + Response.StatusCode);

如果你能分享一些关于这个问题的智慧,那将非常感激。 :)

private static void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {

        HttpWebRequest Request;

        if (m_nAccountTYpe == -1)
        {
            Request = (HttpWebRequest)WebRequest.Create  (XMLObjects.POST_STREAM_DEMO_URI);
        }
        else
        {
            Request = (HttpWebRequest)WebRequest.Create(XMLObjects.POST_STREAM_URI);
        }

        Request.Method = "POST";
        byte[] requestedBytes = Encoding.UTF8.GetBytes(XMLRequests.BuildPushStreamXML());


        Stream RequestStream = Request.GetRequestStream();
        RequestStream.Write(requestedBytes, 0, requestedBytes.Length);
        RequestStream.Close();


        try
        {
            // Create HTTP Response object
            Response = (HttpWebResponse)Request.GetResponse();
            Stream ResponseStream = Response.GetResponseStream();

            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ConformanceLevel = ConformanceLevel.Fragment;

            XmlReader reader = XmlReader.Create(ResponseStream, settings);


            do
            {

                if (e.Cancel)
                {  
                    return;
                }

                if (!reader.EOF)
                {
                    ExtractDataFromStream(reader);
                }
                else
                {
                    throw new Exception("EOF");
                }


            } while (bwStreamData.IsBusy);


        }
        catch (Exception f)
        {

        }
        finally
        {
            Response.Close();
            RequestStream.Close();
            bwStreamData.CancelAsync();
        }
    }

2 个答案:

答案 0 :(得分:0)

我将尝试通过不修改过多的原始代码来提供解决方案。我认为,当您熟悉使用BW时,您会发现更好的方法(包括逻辑)。因此,我将尝试解决您的主要问题。

首先,你是对的,BackgroundWorkers确实有你应该坚持的“设计”范例,可以让你保持线程安全。

首先,BW的逻辑表面上很简单。

1。)DoWork,这是BackgroundWorker的肉/土豆。这是确保读取或保存所有变量,执行函数等的好地方。

2。)ReportProgress,一个在一个BackgroundWorker DoWork迭代结束时触发ASYNCHRONOUSLY的函数。稍等一下。

3。)WorkCompleted,BackgroundWorker的终结性,并在BW操作结束时执行函数。

现在通常的“问题”来自在DoWork中间执行UI或主线程代码。这里的Debug / Console WriteLine命令通常会崩溃或根本不执行。但是,使用ReportProgress事件可以在BackgroundWorker仍在运行时发送UI更新。这可能是您需要修改的代码部分,以便显示命令。

    BW.WorkerReportsProgress = true;
    BW.WorkerSupportsCancellation = true;
    BW.DoWork += new DoWorkEventHandler(BW_DoWork);
    BW.ProgressChanged += new ProgressChangedEventHandler(BW_ProgressChanged);
    BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BW_WorkCompleted);

    private void BW_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Console.WriteLine("Connection Lost. Current Status Code " + Response.StatusCode);
    }

现在您的后台工作者已正确配置,必须非常小心以避免交叉线程。我建议执行一个Try / Catch来处理一个变量的跨线程访问实例(尽可能避免它)。它确实发生了,如果不经常,如果小心。或者,您可以使用Invoke命令的概念。但是设计风格,我留给你。

        do
        {

        if (e.Cancel)
        {  
           return;
        }
        if (!reader.EOF)
        {
           ExtractDataFromStream(reader);
        }
        else
        {
            throw new Exception("EOF");
        }

        MONITOR.ReportProgress(0);

     } while (bwStreamData.IsBusy);

报告进度最初设计用于发送已完成工作的整数“百分比”,但是,使用无限循环概念,您可以使用ReportProgress向用户/程序员传达其他有用的信息。

有一点需要注意,正如我最近所了解的那样,ReportProgress是非顺序的。这意味着它开始执行第二个被调用但BackgroundWorker不会暂停等待它完成!

建议您可能希望包含在BackgroundWorker中的逻辑:

CONTINUE = true;

while((CONTINUE)&&(!(reader.EOF)))
{
   if(StillConnected())
   {
      try
      {
          ExtractDataFromStream(reader);
      }
      catch (Exception ex)
      {
          CONTINUE = False;

          //Because we are on a separate thread, we can't update
          //the UI directly.  So we save the error message to a
          //global variable (string.)
          strErrorMessage = "Exception: " + ex.Message +
                            "\n\nStackTrace: " + ex.StackTrace;
      }
   }
   else
   {
      //To prevent infinite stuck loops, i.e. website goes down
      //try a counter
      if (RECONNECTCOUNT <= 1000)
      {
          Reconnect();
          RECONNECTCOUNT++;
      }
      else
      {
          CONTINUE = false;
          RECONNECTCOUNT = 0;
      }
   }

   //ProgressChanged Event can be used for reading data, saving data,
   //updating the UI, etc.
   BW.ReportProgress(0);
}

为了更好地衡量,每当我取消我的异步状态更新程序时,我都记得调用BW.CancelAsync();以及设置全局变量CONTINUE = false;

答案 1 :(得分:0)

这是RagingCain在原始代码块中替换do while循环的解决方案。感谢您的回答,RagingCain。请注意,我使用其余的原始代码,包括Response变量。

            bool mContinue = true;
            int mReconnectCount = 0;

            while ((mContinue) && (!(reader.EOF)))
            {
                if (Response.StatusCode == System.Net.HttpStatusCode.OK)
                {
                    try
                    {
                        ExtractDataFromStream(reader);
                    }
                    catch (Exception ex)
                    {
                        mContinue = false;

                        //Because we are on a separate thread, we can't update
                        //the UI directly.  So we save the error message to a
                        //global variable (string.)
                        string strErrorMessage = "Exception: " + ex.Message + "\n\nStackTrace: " + ex.StackTrace;
                        Console.WriteLine(strErrorMessage);

                    }
                }
                else
                {
                    //To prevent infinite stuck loops, i.e. website goes down
                    //try a counter
                    if (mReconnectCount <= 1000)
                    {
                        TryToReconnect();

                        mReconnectCount++;
                    }
                    else
                    {
                        mContinue = false;
                        mReconnectCount = 0;
                    }
                }

                //ProgressChanged Event can be used for reading data, saving data, etc.
                BW.ReportProgress(0);
            }

但是我仍然没有得到报告进度,即使我在下面放置了这些代码行并通过了所有调试。我想我想在控制台应用程序运行时迭代地获得这个“当前连接状态正常”消息。但我没有收到Report Progress的消息。任何想法都会非常感激。 :)

        BW = new System.ComponentModel.BackgroundWorker();

        BW.WorkerReportsProgress = true;
        BW.WorkerSupportsCancellation = true;


        BW.DoWork += new System.ComponentModel.DoWorkEventHandler(BW_DoWork);
        BW.ProgressChanged += new ProgressChangedEventHandler(BW_ProgressChanged);
        BW.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(BW_RunWorkerCompleted);



    private static void BW_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        Console.WriteLine("Current Connection Status " + Response.StatusCode);
    }