multithreading problem

M

Mark Irvine

Hi,

I have a small app that uses a custom proxy to down load XML from a web
service. I using the HtpWebRequest/Response objects and the Begin methods.
Initially this process was started on the UI thread and everything worked
ok. However I want the UI thread to create a new thread and start the
request from there. The problem is that every third time I request the
data, the app locks up. I have used the AutoResetEvent class to make the
worker thread wait until the response has been processed, however the app
still crashes. Can anyone offer any help? The code is as follows:

using System;
using System.IO;
using System.Xml;
using System.Net;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Collections;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace WebService
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox txtMain;
private System.Windows.Forms.TextBox txtContentLength;
private System.Windows.Forms.TextBox txtType;
private System.Windows.Forms.Label lblRecomposingData;
private System.Windows.Forms.Label lblContentLength;
private System.Windows.Forms.Label lblType;
private System.Windows.Forms.Button btnGet;
private System.Windows.Forms.Button btnExit;
private System.Windows.Forms.ProgressBar pbStatus;
private System.Windows.Forms.MainMenu mmTmp;
private byte[] dataBuffer;
private MemoryStream msResponse;
private XmlDocument xdTmp;
private int intBytesRead;
private int intMaxBytes;
private int intMaxRead = 1024;
private int intGettingData;
private object objType;
private Thread tWorker;
private AutoResetEvent areEvent;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.mmTmp = new System.Windows.Forms.MainMenu();
this.txtMain = new System.Windows.Forms.TextBox();
this.btnGet = new System.Windows.Forms.Button();
this.btnExit = new System.Windows.Forms.Button();
this.pbStatus = new System.Windows.Forms.ProgressBar();
this.lblContentLength = new System.Windows.Forms.Label();
this.lblType = new System.Windows.Forms.Label();
this.txtContentLength = new System.Windows.Forms.TextBox();
this.txtType = new System.Windows.Forms.TextBox();
this.lblRecomposingData = new System.Windows.Forms.Label();
//
// txtMain
//
this.txtMain.Location = new System.Drawing.Point(5, 5);
this.txtMain.Multiline = true;
this.txtMain.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtMain.Size = new System.Drawing.Size(225, 135);
this.txtMain.Text = "";
//
// btnGet
//
this.btnGet.Location = new System.Drawing.Point(5, 205);
this.btnGet.Text = "Get";
this.btnGet.Click += new System.EventHandler(this.btnGet_Click);
//
// btnExit
//
this.btnExit.Location = new System.Drawing.Point(165, 230);
this.btnExit.Text = "Exit";
this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
//
// pbStatus
//
this.pbStatus.Location = new System.Drawing.Point(0, 230);
//
// lblContentLength
//
this.lblContentLength.Location = new System.Drawing.Point(5, 150);
this.lblContentLength.Size = new System.Drawing.Size(90, 20);
this.lblContentLength.Text = "Content Length";
//
// lblType
//
this.lblType.Location = new System.Drawing.Point(5, 180);
this.lblType.Size = new System.Drawing.Size(90, 20);
this.lblType.Text = "Type";
//
// txtContentLength
//
this.txtContentLength.Location = new System.Drawing.Point(105, 150);
this.txtContentLength.ReadOnly = true;
this.txtContentLength.Size = new System.Drawing.Size(120, 20);
this.txtContentLength.Text = "";
//
// txtType
//
this.txtType.Location = new System.Drawing.Point(105, 180);
this.txtType.ReadOnly = true;
this.txtType.Size = new System.Drawing.Size(120, 20);
this.txtType.Text = "";
//
// lblRecomposingData
//
this.lblRecomposingData.Location = new System.Drawing.Point(5, 250);
this.lblRecomposingData.Size = new System.Drawing.Size(200, 20);
this.lblRecomposingData.Text = "Recomposing Data...";
this.lblRecomposingData.Visible = false;
//
// Form1
//
this.Controls.Add(this.lblRecomposingData);
this.Controls.Add(this.txtType);
this.Controls.Add(this.txtContentLength);
this.Controls.Add(this.lblType);
this.Controls.Add(this.lblContentLength);
this.Controls.Add(this.pbStatus);
this.Controls.Add(this.btnExit);
this.Controls.Add(this.btnGet);
this.Controls.Add(this.txtMain);
this.MaximizeBox = false;
this.Menu = this.mmTmp;
this.MinimizeBox = false;
this.Text = "async web service";
this.Load += new System.EventHandler(this.Form1_Load);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Application.Run(new Form1());
}
private byte[] BuildSoap(SoapDataIn sdiData)
{
//Declare and initialise variables
MemoryStream msEnvelope = new MemoryStream();
XmlTextWriter xtwEnvelope = new XmlTextWriter(msEnvelope,
System.Text.Encoding.UTF8);
//Write start of xml document - root and encoding declaration
xtwEnvelope.WriteStartDocument();
//Write soap envelope element
xtwEnvelope.WriteStartElement("soap", "Envelope",
"http://schemas.xmlsoap.org/soap/envelope/");
//Append xsi and xsd attributes
xtwEnvelope.WriteAttributeString("xmlns", "xsi", null,
"http://www.w3.org/2001/XMLSchema-instance");
xtwEnvelope.WriteAttributeString("xmlns", "xsd", null,
"http://www.w3.org/2001/XMLSchema");
//Write soap body element
xtwEnvelope.WriteStartElement("Body",
"http://schemas.xmlsoap.org/soap/envelope/");
//Write GetXml element to match remote method
xtwEnvelope.WriteStartElement("GetXml", "http://tmp/webservices/test");
//Write intTest element to match parameter for GetXml method
foreach(NameValue nvPair in sdiData.All())
{
xtwEnvelope.WriteElementString(nvPair.Name.ToString(),
"http://tmp/webservices/test", nvPair.Value.ToString());
}
//Close all open elements
xtwEnvelope.WriteEndElement();
xtwEnvelope.WriteEndElement();
xtwEnvelope.WriteEndElement();
//Close xml document
xtwEnvelope.WriteEndDocument();
//Flush the contets of the MemoryStream
xtwEnvelope.Flush();
//Set the position of the MemoryStream in prep for loading into XmlDocument
msEnvelope.Position = 0;
//Close MemoryStream and XmlTextWriter
msEnvelope.Close();
xtwEnvelope.Close();
return msEnvelope.ToArray();
}
private void SendSoapRequest(byte[] bBuffer, string strUri, string
strSoapHeader)
{
HttpWebRequest hwrRequest = (HttpWebRequest)HttpWebRequest.Create(strUri);
hwrRequest.Method = "POST";
hwrRequest.KeepAlive = false;
hwrRequest.ContentType = "text/xml; charset=utf-8";
hwrRequest.ContentLength = bBuffer.Length;
hwrRequest.Headers.Add("SOAPAction", strSoapHeader);
Stream s = hwrRequest.GetRequestStream();
s.Write(bBuffer, 0, bBuffer.Length);
s.Close();
s = null;
hwrRequest.BeginGetResponse(new AsyncCallback(ResponseRecieved),
hwrRequest);
}
private void StartGet()
{
SoapDataIn sdiData = new SoapDataIn();
sdiData.Add("intTest", "87");
sdiData.Add("strDate", "24/04/1980");
this.SendSoapRequest(this.BuildSoap(sdiData),
"http://10.0.3.167:8080/heat_ws_v2/wsTest.asmx",
"http://tmp/webservices/test/GetXml");
this.areEvent.WaitOne();
}
private void btnGet_Click(object sender, System.EventArgs e)
{
try
{
this.btnGet.Enabled = false;
this.areEvent = new AutoResetEvent(false);
Cursor.Current = Cursors.WaitCursor;
this.txtMain.Text = String.Empty;
this.txtContentLength.Text = String.Empty;
this.txtType.Text = String.Empty;
this.intBytesRead = 0;
this.msResponse = new MemoryStream();
this.dataBuffer = new byte[this.intMaxRead];
System.Threading.Interlocked.Exchange(ref this.intGettingData, 1);
this.tWorker = new Thread(new ThreadStart(StartGet));
this.tWorker.Start();
//Cursor.Current = Cursors.Default;
}
catch(Exception ex)
{
MessageBox.Show("Get button's click event handler generated the following
exception:\r\n\r\n" + ex.ToString());
}
}
private void ResponseRecieved(IAsyncResult iarResponse)
{
try
{
MessageBox.Show("h1");
//Set the value of MaxBytes to the content length in a thread safe manner
HttpWebResponse hwrResponse =
(HttpWebResponse)((HttpWebRequest)iarResponse.AsyncState).EndGetResponse(iar
Response);
System.Threading.Interlocked.Exchange(ref this.intMaxBytes,
(int)hwrResponse.ContentLength);
//Set the value of MaxBytes to the content length in a thread safe manner
System.Threading.Interlocked.Exchange(ref objType,
(object)hwrResponse.ContentType.Substring(0,
hwrResponse.ContentType.IndexOf(";")));
//Set progress bar max value to MaxBytes;
this.pbStatus.Invoke(new EventHandler(SetProgressMax));
Application.DoEvents();
//Display content length and type on screen
this.txtContentLength.Invoke(new
EventHandler(this.SetContentLengthTextBox));
Application.DoEvents();
this.txtType.Invoke(new EventHandler(this.SetTypeTextBox));
Application.DoEvents();
//Read the response.
hwrResponse.GetResponseStream().BeginRead(this.dataBuffer, 0,
this.intMaxRead, new AsyncCallback(OnDataRead), hwrResponse);
}
catch(Exception ex)
{
MessageBox.Show("ResponseRecieved generated the following
exception:\r\n\r\n" + ex.ToString());
}
}
private void OnDataRead(IAsyncResult iarResponse)
{
try
{
MessageBox.Show("h2");
HttpWebResponse hwrResponse = (HttpWebResponse)iarResponse.AsyncState;
System.Threading.Interlocked.Exchange(ref this.intBytesRead,
(int)hwrResponse.GetResponseStream().EndRead(iarResponse));
this.pbStatus.Invoke(new EventHandler(UpdateProgressBar));
Application.DoEvents();
this.msResponse.Write(this.dataBuffer, 0, this.intBytesRead);
if(this.intBytesRead > 0)
{
hwrResponse.GetResponseStream().BeginRead(this.dataBuffer, 0,
this.intMaxRead, new AsyncCallback(OnDataRead), hwrResponse);
}
else
{
this.Invoke(new EventHandler(AllDone));
Application.DoEvents();
}
}
catch(Exception ex)
{
MessageBox.Show("OnDataRead generated the following exception:\r\n\r\n" +
ex.ToString());
}
}
private void btnExit_Click(object sender, System.EventArgs e)
{
if(this.intGettingData == 1)
{
MessageBox.Show("Can't exit getting data...");
}
else
{
Application.Exit();
}
}
private void AllDone(object sender, EventArgs e)
{
try
{
MessageBox.Show("h3");
this.Invoke(new EventHandler(this.ShowRecomposingData));
Application.DoEvents();
this.msResponse.Flush();
this.msResponse.Seek(0, System.IO.SeekOrigin.Begin);
this.xdTmp = new XmlDocument();
this.xdTmp.Load(this.msResponse);
this.msResponse.Close();
XmlNodeList nlTmp =
this.xdTmp.DocumentElement.GetElementsByTagName("GetXmlResponse",
"http://tmp/webservices/test");
this.txtMain.Text = nlTmp[0]["GetXmlResult",
"http://tmp/webservices/test"].InnerText;
//this.txtMain.Text = nlTmp[0]["xdTmp",
"http://tmp/webservices/test"].InnerXml;
}
catch(Exception ex)
{
MessageBox.Show("AllDone generated the following exception:\r\n\r\n" +
ex.ToString());
}
finally
{
this.Invoke(new EventHandler(this.CompleteAllDone));
Application.DoEvents();
this.Invoke(new EventHandler(this.ResetProgressBarStatus));
Application.DoEvents();
this.Invoke(new EventHandler(this.HideRecomposingData));
Application.DoEvents();
Cursor.Current = Cursors.Default;
}
}
private void CompleteAllDone(object sender, EventArgs e)
{
this.msResponse = null;
this.dataBuffer = null;
this.xdTmp = null;
this.objType = null;
this.intBytesRead = 0;
this.intMaxBytes = 0;
this.btnGet.Enabled = true;
System.Threading.Interlocked.Exchange(ref this.intGettingData, 0);
this.areEvent.Set();
Application.DoEvents();
}
private void ShowRecomposingData(object sender, EventArgs e)
{
this.lblRecomposingData.Visible = true;
Application.DoEvents();
}
private void HideRecomposingData(object sender, EventArgs e)
{
this.lblRecomposingData.Visible = false;
Application.DoEvents();
}
private void SetContentLengthTextBox(object sender, EventArgs e)
{
this.txtContentLength.Text = this.intMaxBytes.ToString();
Application.DoEvents();
}
private void SetTypeTextBox(object sender, EventArgs e)
{
this.txtType.Text = this.objType.ToString();
Application.DoEvents();
}
private void SetProgressMax(object sender, EventArgs e)
{
try
{
this.pbStatus.Maximum = this.intMaxBytes;
Application.DoEvents();
}
catch(Exception ex)
{
MessageBox.Show("SetProgressMax generated the following exception:\r\n\r\n"
+ ex.ToString());
}
}
private void UpdateProgressBar(object sender, EventArgs e)
{
try
{
this.pbStatus.Value += this.intBytesRead;
Application.DoEvents();
}
catch(Exception ex)
{
MessageBox.Show("UpdateProgressBar generated the following
exception:\r\n\r\n " + ex.ToString());
}
}
private void ResetProgressBarStatus(object sender, EventArgs e)
{
this.pbStatus.Value = this.pbStatus.Minimum;
Application.DoEvents();
}
private void Form1_Load(object sender, System.EventArgs e)
{
this.intGettingData = 0;
}
}
public struct NameValue
{
public NameValue(object objName, object objValue)
{
this.Name = objName;
this.Value = objValue;
}
public object Name;
public object Value;
}
public class SoapDataIn
{
public SoapDataIn()
{
this.alPair = new ArrayList();
}
public bool Add(string strName, string strValue)
{
try
{
this.alPair.Add(new NameValue(strName, strValue));
}
catch
{
return false;
}
return true;
}
public object[] All()
{
return this.alPair.ToArray();
}
private ArrayList alPair;
}
}
 
J

Jon Skeet [C# MVP]

Mark Irvine said:
I have a small app that uses a custom proxy to down load XML from a web
service. I using the HtpWebRequest/Response objects and the Begin methods.
Initially this process was started on the UI thread and everything worked
ok. However I want the UI thread to create a new thread and start the
request from there. The problem is that every third time I request the
data, the app locks up. I have used the AutoResetEvent class to make the
worker thread wait until the response has been processed, however the app
still crashes. Can anyone offer any help? The code is as follows:

I believe the problem is that you're not closing the WebResponse - I've
seen similar behaviour.

Btw, you shouldn't need to use Application.DoEvents at all, usually -
and certainly not from a non-UI thread.
 
M

Mark Irvine

Jon,

Many thanks for your very prompt reply. Using quite a few MessageBox's I
had found the line that the app appeared to crash on and it was:

hwrRequest.GetRequestStream().

I was still no closer to the solution though, but after doing as you
suggested the app works perfectly!!!

Thanks for the tip about using Application.DoEvents, the reason I put them
in was after reading an article on msdn (can't remember which one) - until
that point I didn't even know about the method. If they're serving no
purpose, probably causing a performance hit, I will remove them.

Thanks again,

Mark
 
J

Jon Skeet [C# MVP]

Mark Irvine said:
Many thanks for your very prompt reply. Using quite a few MessageBox's I
had found the line that the app appeared to crash on and it was:

hwrRequest.GetRequestStream().

I was still no closer to the solution though, but after doing as you
suggested the app works perfectly!!!

Excellent - glad to hear it.
Thanks for the tip about using Application.DoEvents, the reason I put
them in was after reading an article on msdn (can't remember which
one) - until that point I didn't even know about the method. If
they're serving no purpose, probably causing a performance hit, I
will remove them.

It's more that they're confusing if they're not helpful, really. I can
only remember one time when I needed to use it myself, which was when I
wanted some UI effects to take hold but wanted to then do something
else in the UI thread.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top