I have a problem with a small C# application.
The application has to connect through a serial port to a bar code scanner which reads a Data Matrix code. The Data Matrix code represents an array of bytes which is a zip archive. I read a lot about the way SerialPort.DataReceived work but I can't find an elegant solution to my problem. And the application should work with different bar code scanners so i can't make it scanner specific. Here is some of my code:
using System;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;
using Ionic.Zip;
namespace SIUI_PE
{
public partial class Form1 : Form
{
SerialPort _serialPort;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
_serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.ToString());
return;
}
_serialPort.Handshake = Handshake.None;
_serialPort.ReadBufferSize = 10000;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
_serialPort.Open();
}
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[10000];
_serialPort.Read(data, 0, 10000);
File.WriteAllBytes(Directory.GetCurrentDirectory() + "/temp/fis.zip", data);
try
{
using (ZipFile zip = ZipFile.Read(Directory.GetCurrentDirectory() + "/temp/fis.zip"))
{
foreach (ZipEntry ZE in zip)
{
ZE.Extract(Directory.GetCurrentDirectory() + "/temp");
}
}
File.Delete(Directory.GetCurrentDirectory() + "/temp/fis.zip");
}
catch (Exception ex1)
{
MessageBox.Show("Corrupt Archive: " + ex1.ToString());
}
}
}
}
So my question is: How can I know that I read all the bytes the scanner sent?
The code I've got for reading barcode data, which has been working flawlessly in production for several years looks like this:
Note, my app has to read standard UPC barcodes as well as GS1 DataBar, so there's a bit of code you may not need...
The key line in this is:
string ScanData = ScannerPort.ReadExisting();
which is found in the DoScan section, and simply reads the scan data as a string. It bypasses the need to know how many bytes are sent, and makes the rest of the code easier to deal with.
// This snippet is in the Form_Load event, and it initializes teh scanner
InitializeScanner();
ScannerPort.ReadExisting();
System.Threading.Thread.Sleep(1000);
// ens snippet from Form_Load.
this.ScannerPort.DataReceived += new SerialDataReceivedEventHandler(ScannerPort_DataReceived);
delegate void DoScanCallback(); // used for updating the form UI
void DoScan()
{
if (this.txtCouponCount.InvokeRequired)
{
DoScanCallback d = new DoScanCallback(DoScan);
this.Invoke(d);
return;
}
System.Threading.Thread.Sleep(100);
string ScanData = ScannerPort.ReadExisting();
if (isInScanMode)
{
try
{
HandleScanData(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Invalid Scan");
}
}
}
void ScannerPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// this call to sleep allows the scanner to receive the entire scan.
// without this sleep, we've found that we get only a partial scan.
try
{
DoScan();
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to handle scan event in ScannerPort_DataReceived." + System.Environment.NewLine + ex.ToString());
}
}
void Port_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show(e.EventType.ToString());
}
private void HandleScanData(string ScanData)
{
//MessageBox.Show(ScanData + System.Environment.NewLine + ScanData.Length.ToString());
//Determine which type of barcode has been scanned, and handle appropriately.
if (ScanData.StartsWith("A") && ScanData.Length == 14)
{
try
{
ProcessUpcCoupon(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to process UPC coupon data" + System.Environment.NewLine + ex.ToString());
}
}
else if (ScanData.StartsWith("8110"))
{
try
{
ProcessDataBarCoupon(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to process DataBar coupon data" + System.Environment.NewLine + ex.ToString());
}
}
else
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Invalid Scan" + System.Environment.NewLine + ScanData);
}
}
private void InitializeScanner()
{
try
{
ScannerPort.PortName = Properties.Settings.Default.ScannerPort;
ScannerPort.ReadBufferSize = Properties.Settings.Default.ScannerReadBufferSize;
ScannerPort.Open();
ScannerPort.BaudRate = Properties.Settings.Default.ScannerBaudRate;
ScannerPort.DataBits = Properties.Settings.Default.ScannerDataBit;
ScannerPort.StopBits = Properties.Settings.Default.ScannerStopBit;
ScannerPort.Parity = Properties.Settings.Default.ScannerParity;
ScannerPort.ReadTimeout = Properties.Settings.Default.ScannerReadTimeout;
ScannerPort.DtrEnable = Properties.Settings.Default.ScannerDtrEnable;
ScannerPort.RtsEnable = Properties.Settings.Default.ScannerRtsEnable;
}
catch (Exception ex)
{
MessageBox.Show("Unable to initialize scanner. The error message received will be shown next. You should close this program and try again. If the problem persists, please contact support.", "Error initializing scanner");
MessageBox.Show(ex.Message);
Application.Exit();
}
}
As stated in the doc for SerialPort.DataReceived, "Use the BytesToRead property to determine how much data is left to be read in the buffer."
here is the doc for SerialPort.BytesToRead
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread.aspx
Related
I've created a Arduino + windows 10 app. The microcontroller connects with a Wi-Fi module (ESP8266-ESP01), tcp/ip protocol. The module is the server and app is the client. The module works fine and I tested it on another program ("SocketTest v3.0"). It sends and receives data. But my app can only write data, the socket.InputStream doesn't work. When I read data, it throws an error.
What am I doing wrong?
Maybe there is an example like this program:
.
public sealed partial class MainPage : Page
{
StreamSocket _socket;
HostName _hostName;
DataWriter writer;
public MainPage()
{
this.InitializeComponent();
_socket = new StreamSocket();
}
private async void connectButton_Click(object sender, RoutedEventArgs e)
{
#region _check_parameters
if (String.IsNullOrEmpty(hostName_Box.Text))
{
_statusBar.Text += "[ERROR] Set the Host Name !!!\n";
return;
}
if (String.IsNullOrEmpty(serviceName_Box.Text))
{
_statusBar.Text += "[ERROR] Set the Service Name !!!\n";
return;
}
try
{
_hostName = new HostName(hostName_Box.Text);
}
catch (Exception)
{
_statusBar.Text += "[ERROR] Invalid Host Name !!!\n";
return;
}
#endregion
// If necessary, tweak the socket's control options before carrying out the connect operation.
// Refer to the StreamSocketControl class' MSDN documentation for the full list of control options.
_socket.Control.KeepAlive = false;
try
{
_statusBar.Text += "Connecting...\n";
await _socket.ConnectAsync(_hostName, serviceName_Box.Text);
_statusBar.Text += "Connected\n";
// go to send mode
connectButton.Content = "Send";
connectButton.Click -= connectButton_Click;
connectButton.Click += send_Data;
hostName_Box.PlaceholderText = "data to send";
hostName_Box.Text = "";
writer = new DataWriter(_socket.OutputStream);
}
catch(Exception exception)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
_statusBar.Text += "[ERROR] Connect failed with error:\n" + exception.Message + "\n";
}
}
private async void read_data()
{
DataReader dataReader = new DataReader(_socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
try
{
await dataReader.LoadAsync(dataReader.UnconsumedBufferLength);
string s;
uint length;
length = dataReader.ReadUInt32();
s = dataReader.ReadString(length);
_statusBar.Text += "Read successful\n" + s + "\n";
}
catch (Exception exception)
{
_statusBar.Text += "[ERROR] Fail to load dada !!!\n" +
exception.Message + "\n";
}
}
private async void send_Data(object sender, RoutedEventArgs e)
{
if (String.IsNullOrEmpty(hostName_Box.Text))
{
_statusBar.Text += "Write anything\n";
return;
}
if(hostName_Box.Text == "read")
{
try
{
hostName_Box.Text = "";
read_data();
return;
}
catch (Exception ex)
{
_statusBar.Text += "[ERROR] Reading data failed:\n" + ex.Message + "\n";
}
}
writer.WriteUInt32(writer.MeasureString(hostName_Box.Text));
writer.WriteString(hostName_Box.Text);
try
{
await writer.StoreAsync();
_statusBar.Text += "\"" + hostName_Box.Text + "\" sent successfully\n";
hostName_Box.Text = "";
}
catch(Exception ex)
{
if (SocketError.GetStatus(ex.HResult) == SocketErrorStatus.Unknown)
{
throw;
}
_statusBar.Text += "[ERROR] Send failed with error:\n" + ex.Message + "\n";
}
}
}
Maybe my reading function is not so good, but the error is that in every situation
dataReader.UnconsumedBufferLength == 0;
and when I use:
int length = dataReader.ReadInt32();
it throws an exception.
The first error is that the dataReader.UnconsumedBufferLength == 0. And the function .LoadAsync(...) throws the error.
DataReader.UnconsumedBufferLength is used to get the size of the buffer that has not been read. You haven't loaded any data from the input stream to the intermediate buffer before you called dataReader.UnconsumedBufferLength, so the value is 0. And the parameter of DataReader.LoadAsync cannot be zero, so you got a System.ArgumentException: The parameter is incorrect.
If I send a string "qwerty" and do dataReader.LoadAsync(6) it throws --> "The operation attempted to acces data outside the valid range"
This exception is thrown by the code s = dataReader.ReadString(length);, you need to call await dataReader.LoadAsync(length); to load the string data into the buffer before you can read it.
Following is the sample code I have verified:
private async void read_data()
{
DataReader dataReader = new DataReader(_socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
try
{
//load some data to the buffer first
await dataReader.LoadAsync(4);
//read int data
uint length = dataReader.ReadUInt32();
//load data to the buffer before reading it.
uint acturalStringLength = await dataReader.LoadAsync(length);
//read string data
string s = dataReader.ReadString(acturalStringLength);
_statusBar.Text += "Read successful\n" + s + "\n";
}
catch (Exception exception)
{
_statusBar.Text += "[ERROR] Fail to load dada !!!\n" +
exception.Message + "\n";
}
}
I am trying to build a simple code that joins csv files into one distinct file, but my background worker seems to have a mind of its own and my code gets stuck every time.
Here is my code for joining the file using the background worker:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
int fileTotalLines = File.ReadAllLines(file).Length;
this.Invoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
}));
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
}
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
backgroundWorker.ReportProgress((rowsCount * 100 / fileTotalLines), (int)ProgressType.Row);
if (backgroundWorker.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
}
}
}
}
backgroundWorker.ReportProgress(0, (int)ProgressType.Row);
backgroundWorker.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
backgroundWorker.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
}
catch (Exception ex) { }
}
When I run in debug mode and go with the debugger I don't see any problems, but when I let the code run it self it gets stuck and crashes.
Can someone PLEASE help me and tell me what am I missing out here ?
Here is the exception:
Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in
'C:\Users\Develop\Desktop\ExcelBuilder\ExcelBuilder\bin\Debug\ExcelBuilder.vshost.exe'.
Additional information: The CLR has been unable to transition from COM context 0x90fb78
to COM context 0x90fc30 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or processing a very
long running operation without pumping Windows messages. This situation generally has
a negative performance impact and may even lead to the application becoming non
responsive or memory usage accumulating continually over time. To avoid this problem,
all single threaded apartment (STA) threads should use pumping wait primitives
(such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.
I did a small example of your program, trying to guess what it must do (https://github.com/anderson-rancan/stackoverflow_28798348, drag and drop 4 files to the groupbox, lorem?.csv), and there is a few things that you should consider:
never try/catch a unknown exception, every exception or something you cannot deal with (https://msdn.microsoft.com/en-us/library/ms182137.aspx)
when using a BackgroundWorker on a form, use the "sender" for references to it, it's a thread safe object to your method (https://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx)
maybe you are updating too fast your form, change your Invoke method to BeingInvoke, and do the update async (https://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx)
So, just fixing that was possible to run it, like this:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bckw = (BackgroundWorker)sender; // Recommended way, thread safe
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
double fileTotalLines = File.ReadAllLines(file).Length;
this.BeginInvoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
})); // Invoke async, way too fast this...
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
} // why are you using that? it won't get TRUE
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
bckw.ReportProgress((int)Math.Round(rowsCount * 100 / fileTotalLines, 0), (int)ProgressType.Row);
if (bckw.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
throw; // Throw it again, or you won't know the Exception
}
}
}
}
bckw.ReportProgress(0, (int)ProgressType.Row);
bckw.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
bckw.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//try
//{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
if (e.ProgressPercentage <= fileProgressBar.Maximum)
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
//}
//catch (Exception ex) { } // Don't catch everything
}
Finally, may I suggest another approach?
You're reading the file two times: one to get the number of lines, and another to read each line. Try to do this just once, you'll get a better result.
I have a small problem. Now I have written my code, and it works excellent, but I'm trying to do it better.
I receive data from a device, but now I will upgrade it to receive data from more devices.
To this I have made a string called adress, this is the string which should be looked at. If this string is for example 111222333, then the data received should be saven in chart 1. But if this string is for example 333aaa444, then the data received should be saven in chart 2.
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
recievdata = SerialPort.ReadExisting();
string adress = recievdata.Substring(7, 16);
this.Invoke(new EventHandler(DisplayText));
using (Stream stream2 = File.Open(path, FileMode.Append))
using (StreamWriter sWriter1 = new StreamWriter(stream2))
{
if (adress )
if (recievdata.Contains("UCAST") && recievdata.Contains("=g"))
{
sWriter1.Write(DateTime.Now.ToString("HH:mm:ss"));
sWriter1.Write(" ; ");
sWriter1.WriteLine(1);
if (SleepMovChar.InvokeRequired)
{
SleepMovChar.Invoke(new MethodInvoker(delegate
{ SleepMovChar.Series["Bevægelse"].Points.AddXY(DateTime.Now.ToString("HH:mm:ss"), 1); }));
SleepMovChar.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
}
}
else
{
timer1.Tick += new EventHandler(timer1_Tick);
}
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
Hope that you can help me.
Thanks.
I am currently working on C# application which requires to read serial port. In UI, there is a ON/OFF button which enables user click on it to start and stop reading data from serial port. If I continuously click on the button on and off. It threw an exception - Access to COM3 is denied or even said "The device is not connected". Can anyone suggest a better way to implement the serial port function which is able to resolve the situation as described above? Here is the code I use:
**// Start reading data from serial port**
public override void StartReading(string portname)
{
try
{
int k = int.Parse(portname.Replace("COM", ""));
if (startThread != null)
{
startThread.Abort();
startThread = null;
}
startThread = new Thread(new ThreadStart(delegate
{
isActive = true;
try
{
using (SerialPort sp = new SerialPort(portname))
{
if (!isActive)
{
DisposeBT(sp);
return;
}
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
if (!isActive)
{
DisposeBT(sp);
return;
}
if (!isActive)
{
DisposeBT(sp);
return;
}
else
{
Thread.Sleep(6500);
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex)
{
Logger.Warn("Failed to open the serial port for HRM once. Try it again.");
Logger.Error(ex);
////////////////////// new added below
if(sp !=null && sp.IsOpen)
{
sp.Dispose();
}
Thread.Sleep(6500);
if (IsPortAvailable(k))
{
try
{
if (sp != null && !sp.IsOpen)
{
sp.Open();
}
}
catch (Exception ex1)
{
////////////////////// new added below
if (sp != null && sp.IsOpen)
{
sp.Dispose();
}
Logger.Warn("Failed to open the serial for HRM twice.");
Logger.Error(ex1);
// return;
}
}
}
}
while (true)
{
if (!isActive)
{
DisposeBT(sp);
break;
}
}
if (!isActive)
{
DisposeBT(sp);
return;
}
DisposeBT(sp);
}
}
catch (Exception ex)
{
Logger.Warn("Exception thrown for HRM.");
Logger.Error(ex);
}
}));
startThread.IsBackground = true;
startThread.Priority = ThreadPriority.Highest;
startThread.Start();
}
catch (Exception ex)
{
Logger.Warn("Failed to start reading for HRM02I3A1 bluetooth device.");
Logger.Error(ex);
}
}
// Stop reading data from serial port
public override void StopReading()
{
try
{
isActive = false;
}
catch { }
}
// event handler for the serial port to read data from sp.
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (isActive)// && startThread.IsAlive
{
SerialPort sp1 = (SerialPort)sender;
try
{
sp1.Read(data, 0, 8);
decoder.Decode(data);
}
catch(Exception ex)
{
Logger.Warn("------data received from Serial Port error for HRM-------");
Logger.Error(ex);
};
}
}
first make background worker thread that accept the cancel event.
in the DoWork method you can write something like that
void DoWork{
// init com port
while(no body cancelled the background worker){
// if there any waiting data receive and process it. do not use event handlers
}
// close the serial port so you can open it again later.
}
Also if you want to cancel the background work it would be a piece of cake
// send cancel command.
// wait till it is canceled.
Try adding startThread.Join() directly after the call to startThread.Abort().
Take a look at the msdn documentation on Thread.Abort and perhaps you also should check what join does.
I'm trying to read from a Uri which i created and to display it on windows phone 7 app.
(I'm doing this tutorial:http://msdn.microsoft.com/en-us/windowsmobile/Video/hh237494).
My problem is that the program doesnt get into the OpenReadCompletedEventHandler and i dont know why. (i putted message box in order to debug and i found out that the program doesnt get into the OpenReadCompletedEventHandler). Here is the relevant code:
void myButton_Click(object sender, RoutedEventArgs e)
{
try
{
WebClient webClient = new WebClient();
Uri uri = new Uri("http://localhost:44705/Service1.svc/GetAllBrands");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
try
{
webClient.OpenWriteAsync(uri);
MessageBox.Show("opening sucsseded");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
MessageBox.Show("OpenRead Handler");
// OpenWriteCompletedEventArgs temp = (OpenWriteCompletedEventArgs)e;
DataContractJsonSerializer serializer = null;
try
{
serializer = new DataContractJsonSerializer(typeof(ObservableCollection<Brand>));
ObservableCollection<Brand> Brands = serializer.ReadObject(e.Result) as ObservableCollection<Brand>;
foreach (Brand b in Brands)
{
int id = b.BrandId;
string name = b.BrandName;
listBrands.Items.Add(id + " " + name);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks in advance!
I have never used this but a quick google takes me to this page on MSDN - http://msdn.microsoft.com/en-us/library/system.net.webclient.openreadcompleted.aspx
This should tell you why it's not working - because you are using a read event for a write operation. You should be using OpenWriteCompletedEventHandler with OpenWriteAsync as per this page on MSDN - http://msdn.microsoft.com/en-us/library/system.net.webclient.openwritecompleted.aspx