我现在面临的问题是微不足道,因为我使用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();
}
}
答案 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);
}