I am getting an error in Tcp Wcf Service hosted on winforms or WPF.
The service either hangs or throws "Thread Exited" error.
The same code works fine in a console application.
Thanks.
Server:
namespace WCFService
{
//interface declarations just like the client but the callback
//decleration is a little different
[ServiceContract]
interface IMessageCallback
{
[OperationContract(IsOneWay = true)]
void OnMessageAdded(string message, DateTime timestamp);
}
//This is a little different than the client
// in that we need to state the SessionMode as required or it will default to "notAllowed"
[ServiceContract(CallbackContract = typeof(IMessageCallback), SessionMode = SessionMode.Required)]
public interface IMessage
{
[OperationContract]
void AddMessage(string message);
[OperationContract]
bool Subscribe();
[OperationContract]
bool Unsubscribe();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class RCRServer : IMessage
{
private static List<IMessageCallback> subscribers = new List<IMessageCallback>();
public ServiceHost host = null;
public void Connect()
{
//I'm doing this next part progromatically instead of in app.cfg
// because I think it makes it easier to understand (and xml is stupid)
host = new ServiceHost(typeof(RCRServer), new Uri("net.tcp://localhost:8000"));
//notice the NetTcpBinding? This allows programs instead of web stuff
// to communicate with each other
host.AddServiceEndpoint(typeof(IMessage), new NetTcpBinding(), "ISubscribe");
try
{
host.Open();
Console.WriteLine("Successfully opened port 8000.");
//Console.ReadLine();
//host.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public bool Subscribe()
{
try
{
//Get the hashCode of the connecting app and store it as a connection
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
if (!subscribers.Contains(callback))
subscribers.Add(callback);
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public bool Unsubscribe()
{
try
{
//remove any connection that is leaving
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
if (subscribers.Contains(callback))
subscribers.Remove(callback);
return true;
}
catch
{
return false;
}
}
public void AddMessage(String message)
{
//Console.WriteLine("Calling OnMessageAdded on callback");
//foreach (Subscriber s in subscribers.Values.ToList())
//{ }
try
{
Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
callback.OnMessageAdded(message, DateTime.Now);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Go through the list of connections and call their callback funciton
//subscribers.ForEach(delegate (IMessageCallback callback)
//{
// //System.Threading.Thread.Sleep(1000);
// if (((ICommunicationObject)callback).State == CommunicationState.Opened)
// {
// Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
// callback.OnMessageAdded(message, DateTime.Now);
// }
// else
// {
// subscribers.Remove(callback);
// }
//});
}
}
}
Client:
namespace WCFClient
{
//These are the interface declerations for the client
[ServiceContract]
interface IMessageCallback
{
//This is the callback interface decleration for the client
[OperationContract(IsOneWay = true)]
void OnMessageAdded(string message, DateTime timestamp);
}
[ServiceContract(CallbackContract = typeof(IMessageCallback))]
public interface IMessage
{
//these are the interface decleratons for the server.
[OperationContract]
void AddMessage(string message);
[OperationContract]
bool Subscribe();
[OperationContract]
bool Unsubscribe();
}
class RCRProxy : IMessageCallback, IDisposable
{
IMessage pipeProxy = null;
//MainWindow mainwindow = new MainWindow();
//public RCRProxy(MainWindow main)
//{
// mainwindow = main;
//}
public bool Connect()
{
//note the "DuplexChannelFactory". This is necessary for Callbacks.
// A regular "ChannelFactory" won't work with callbacks.
DuplexChannelFactory<IMessage> pipeFactory =
new DuplexChannelFactory<IMessage>(
new InstanceContext(this),
new NetTcpBinding(),
new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));
try
{
//Open the channel to the server
pipeProxy = pipeFactory.CreateChannel();
//Now tell the server who is connecting
pipeProxy.Subscribe();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public void Close()
{
pipeProxy.Unsubscribe();
}
//This function sends a string to the server so that it can broadcast
// it to all other clients that have called Subscribe().
public string SendMessage(string message)
{
try
{
System.Threading.Thread.Sleep(1000);
pipeProxy.AddMessage(message);
return "sent >>>> " + message;
}
catch (Exception e)
{
return e.Message;
}
}
//This is the function that the SERVER will call
public void OnMessageAdded(string message, DateTime timestamp)
{
//Console.WriteLine(message + ": " + timestamp.ToString("hh:mm:ss"));
// mainwindow.txtblkStatus.Text = message + ": " + timestamp.ToString("hh:mm:ss");
}
//We need to tell the server that we are leaving
public void Dispose()
{
pipeProxy.Unsubscribe();
}
}
}
namespace StockTickerClient
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public class DataItem
{
public string Symbol { get; set; }
public string Series { get; set; }
public float? AskPrice { get; set; }
public float? BidPrice { get; set; }
public float? LTP { get; set; }
public int? Volume { get; set; }
public string Description { get; set; }
public DateTime? SentDate { get; set; }
public DataItem(string symbol, string series, float? askprice, float? bidprice, float? ltp, int? volume, string
description, DateTime? sentdate)
{
Symbol = symbol;
Series = series;
AskPrice = askprice;
BidPrice = bidprice;
LTP = ltp;
Volume = volume;
Description = description;
SentDate = sentdate;
}
}
public partial class MainWindow : Window
{
private void btnSubscribe_Click(object sender, RoutedEventArgs e)
{
RCRProxy rp = new RCRProxy();
if (rp.Connect() == true)
{
// Console.WriteLine("please space to end session");
string tmp = "Start";// Console.ReadLine();
while (tmp != "Exit")
{
try
{
rp.SendMessage(tmp);
}
catch (Exception ex)
{
txtblkStatus.Text = ex.Message;
}
// tmp = Console.ReadLine();
// txtblkStatus.Text = rp.SendMessage(tmp);
}
}
if (((ICommunicationObject)rp).State == CommunicationState.Opened)
rp.Close();
}
}
}
In the winforms/wpf application the communication between the server and the clients should be done on a secondary thread that is responsible of only that. If you put the action that you have on button btnSubscribe_Click in a new thread, the application will run ok.
See more details of how to work with threads in wpf:
c# wpf run button click on new thread
https://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/
https://msdn.microsoft.com/en-us/library/ms741870(v=vs.85).aspx
Related
I have 50 IMountCmd objects from one or more threads and drop them in a blocking collection. Each is executed and some get results or errors. They are put into a ConcurrentDictionary where I loop for ContainsKey and return the objects. Does this seems thread safe and correct way to process a blocking queue?
public class CmdGetAxisDegrees : IMountCommand
{
public long Id { get; }
public DateTime CreatedUtc { get; private set; }
public bool Successful { get; private set; }
public Exception Exception { get; private set; }
public dynamic Result { get; private set; }
private readonly AxisId _axis;
public CmdGetAxisDegrees(long id, AxisId axis)
{
Id = id;
_axis = axis;
CreatedUtc = HiResDateTime.UtcNow;
Successful = false;
Queues.AddCommand(this);
}
public void Execute(Actions actions)
{
try
{
Result = actions.GetAxisDegrees(_axis);
Successful = true;
}
catch (Exception e)
{
Successful = false;
Exception = e;
}
}
}
private static void ProcessCommandQueue(IMountCommand command)
{
command.Execute(_actions);
if (command.Id > 0)
{
_resultsDictionary.TryAdd(command.Id, command);
}
}
public static IMountCommand GetCommandResult(long id)
{
IMountCommand result;
while (true)
{
if (!_resultsDictionary.ContainsKey(id)) continue;
var success = _resultsDictionary.TryRemove(id, out result);
if (!success)
{
//log
}
break;
}
return result;
}
static Queues()
{
_actions = new Actions();
_resultsDictionary = new ConcurrentDictionary<long, IMountCommand>();
_commandBlockingCollection = new BlockingCollection<IMountCommand>();
Task.Factory.StartNew(() =>
{
foreach (var command in _commandBlockingCollection.GetConsumingEnumerable())
{
ProcessCommandQueue(command);
}
});
}
public interface IMountCommand
{
long Id { get; }
DateTime CreatedUtc { get; }
bool Successful { get; }
Exception Exception { get; }
dynamic Result { get; }
void Execute(Actions actions);
}
I have a websocket connection and I want to make get methods for it. I used this example.
This is a part of the data model:
public class Message
{
public string MessageType { get; set; }
}
public class SensorData : Message
{
public float Temperature { get; set; }
public float Humidity { get; set; }
public float Pressure { get; set; }
}
This is the websocket class:
public WebSocketConnection(string url)
{
socket = new WebSocket(url);
}
private WebSocket socket;
public int Timeout = 10000;
public void Connect()
{
socket.Connect();
socket.OnMessage += Socket_OnMessage;
}
public void Disconnect()
{
socket.Close();
socket.OnMessage -= Socket_OnMessage;
}
public event EventHandler<OnSensorDataEventArgs> SensorDataReveived;
private void Socket_OnMessage(object sender, MessageEventArgs e)
{
var msg = JsonConvert.DeserializeObject<Message>(e.Data);
switch (msg.MessageType)
{
case "other message types":
{
...
}
case "SensorData":
{
SensorDataReveived?.Invoke(this, new OnSensorDataEventArgs(JsonConvert.DeserializeObject<SensorData>(e.Data)));
break;
}
}
}
public Task<SensorData> GetSensorData()
{
var msg = JsonConvert.SerializeObject(new Message() { MessageType = "RequestSensorData" });
var tcs = new TaskCompletionSource<SensorData>();
SensorDataReveived += (sender, e) => {
tcs.SetResult(e.SensorData);
};
socket.Send(msg);
return tcs.Task;
}
The problem is the GetSensorData method. When socket.Send(msg) is called, the websocket server answers and the event is triggered, but after the SetResult call there happens nothing. I already tried TaskCreationOptions.RunContinuationsAsynchronously and wrapping SetResult in a Task.Run but that didn't help.
private async void BtnShowSensorData_Clicked(object sender, EventArgs e)
{
var sensorData = await connection.GetSensorData(); //Connection is an instance of WebSocketConnection
labelTemperature.Text = " Temperature: " + sensorData.Temperature.ToString();
labelHumidity.Text = " Humidity: " + sensorData.Humidity.ToString();
labelPressure.Text = " Pressure: " + sensorData.Pressure.ToString();
}
I have application that host WCF service and I want to return this class object:
namespace classes
{
[DataContract]
public class NetworkAdapter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string ID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public string IPAddress { get; set; }
[DataMember]
private string gatewayIpAddress;
[DataMember]
public string Speed { get; set; }
[DataMember]
public string NetworkInterfaceType { get; set; }
[DataMember]
public string MacAddress { get; set; }
[DataMember]
private LivePacketDevice livePacketDevice;
[DataMember]
public PacketDevice PacketDevice { get { return livePacketDevice; } }
public NetworkAdapter(LivePacketDevice packetDevice)
{
livePacketDevice = packetDevice;
}
public override string ToString()
{
return Description;
}
public static NetworkAdapter[] getAll()
{
List<NetworkAdapter> list = new List<NetworkAdapter>();
foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
foreach (UnicastIPAddressInformation uniCast in adapter.GetIPProperties().UnicastAddresses)
{
if (!System.Net.IPAddress.IsLoopback(uniCast.Address) && uniCast.Address.AddressFamily != AddressFamily.InterNetworkV6)
{
StringBuilder gatewayIPAddresses = new StringBuilder();
string gatewayIPAddressesDisplay = string.Empty;
foreach (var address in adapter.GetIPProperties().GatewayAddresses)
{
gatewayIPAddresses.Append(address.Address);
gatewayIPAddresses.Append(" ");
}
if (gatewayIPAddresses.Length > 0)
{
gatewayIPAddressesDisplay = gatewayIPAddresses.ToString().TrimEnd(' ');
}
if (!list.Any(l => l.ID == adapter.Id))
{
list.Add(new NetworkAdapter(getDevice(adapter.Id))
{
Name = adapter.Name,
ID = adapter.Id,
Description = adapter.Description,
IPAddress = uniCast.Address.ToString(),
NetworkInterfaceType = adapter.NetworkInterfaceType.ToString(),
Speed = adapter.Speed.ToString("#,##0"),
MacAddress = getMacAddress(adapter.GetPhysicalAddress().ToString()),
gatewayIpAddress = gatewayIPAddressesDisplay
});
}
}
}
//return list.GroupBy(n => n.ID).Select(g => g.FirstOrDefault()).ToArray();
return list.ToArray();
}
private static LivePacketDevice getDevice(string id)
{
return LivePacketDevice.AllLocalMachine.First(x => x.Name.Contains(id));
}
private static string getMacAddress(string oldMAC)
{
int count = 0;
string newMAC = oldMAC;
for (int i = 2; i < oldMAC.Length; i += 2)
{
newMAC = newMAC.Insert(i + count++, ":");
}
return newMAC;
}
public string defaultGateway
{
get
{
if (gatewayIpAddress != "")
{
return gatewayIpAddress;
}
return "n/a";
}
}
private static string getIpFourthSegment(string ipAddress)
{
try
{
string[] arr = ipAddress.Split('.');
return arr[3];
}
catch (Exception)
{
return null;
}
}
}
}
This is my service:
[ServiceContract()]
public interface IService1
{
[OperationContract]
NetworkAdapter[] GetAdapters();
[OperationContract]
string GetDate();
}
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession)]
public class service1 : IService1
{
public NetworkAdapter[] GetAdapters()
{
IEnumerable<NetworkAdapter> adapters = NetworkAdapter.getAll();
return adapters.ToArray();
}
public string GetDate()
{
return DateTime.Now.ToString();
}
}
When I am try to run GetAdapters function got this error:
An unhandled exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll
Additional information: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9599960'.
When try to run GetDate function it works fine and return simple string.
maybe I need to configure my class in other way ? I have added [DataMember] to each member
LivePacketDevice and PacketDevice need to be [DataContract]s, while it might also work if they are just [Serializable]. Otherwise WCF does not know how to transfer them to the client.
Also it is advisable to only transfer objects that just hold data, not functionality, as that functionality will not be available to the client. The stub created on the client side will only contain data fields, not methods, as code is not transferred/cloned.
I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}
I would like to send the character 'a' to the serial port.
I tried:
serialPort1.WriteLine("a");
but it's not actually sending the character 'a' to my board.
Any ideas?
I share to you a class created by me in a productive project. This Handles the serial connection and reading and writing buffer:
public class CommSERIAL : IComm
{
#region Events
public event EventHandler EvtOnConnect;
public event EventHandler EvtOnDisconnect;
public event EventHandler<OnDataReceivedEventArgs> EvtOnDataReceived;
#endregion
System.IO.Ports.SerialPort Rs232 = new System.IO.Ports.SerialPort();
private string m_Port;
public string Port
{
get { return m_Port; }
set { m_Port = value; }
}
private int m_Baud;
public int Baud
{
get { return m_Baud; }
set { m_Baud = value; }
}
private int m_DataBit;
public int DataBit
{
get { return m_DataBit; }
set { m_DataBit = value; }
}
private System.IO.Ports.StopBits m_stopBits;
public System.IO.Ports.StopBits StopBits
{
get { return m_stopBits; }
set { m_stopBits = value; }
}
private System.IO.Ports.Parity m_parity;
public System.IO.Ports.Parity Parity
{
get { return m_parity; }
set { m_parity = value; }
}
public void Connect()
{
if (!(Rs232.IsOpen))
{
Rs232.PortName = this.Port;
Rs232.BaudRate = this.Baud; ;
Rs232.DataBits = this.DataBit;
Rs232.StopBits = this.StopBits;
Rs232.Parity = this.Parity;
Rs232.ReadTimeout = 5000;
Rs232.Handshake = System.IO.Ports.Handshake.None;
Rs232.ReadTimeout = 1000;
Rs232.WriteTimeout = 500;
Rs232.Open();
}
}
public void Disconnect()
{
Rs232.Close();
if (EvtOnDisconnect != null)
EvtOnDisconnect(new object(), new System.EventArgs());
m_Connected = false;
}
public CommSERIAL()
{
this.ConnType = ConnType.Direct;
}
public bool Connected
{
get
{
return m_Connected;
}
}
private ConnType m_ConnType;
public ConnType ConnType
{
get { return m_ConnType; }
set { m_ConnType = value; }
}
public string ReadOnByte(int Lenght,char EndChar)
{
char[] bytes = new char[Lenght];
string ret = "";
int numBytesRead = 0;
while (bytes[numBytesRead] != EndChar && numBytesRead <= bytes.Length)
{
while (Rs232.Read(bytes, numBytesRead, 1) == 1 && bytes[numBytesRead] != EndChar && numBytesRead <= bytes.Length)
{
numBytesRead++;
}
}
foreach (char b in bytes)
ret += b.ToString();
return ret.Substring(0,numBytesRead);
}
public String ReadBuffer()
{
try
{
if (Rs232.IsOpen)
{
Byte[] readBuffer = new Byte[Rs232.ReadBufferSize + 1];
try
{
// If there are bytes available on the serial port,
// Read returns up to "count" bytes, but will not block (wait)
// for the remaining bytes. If there are no bytes available
// on the serial port, Read will block until at least one byte
// is available on the port, up until the ReadTimeout milliseconds
// have elapsed, at which time a TimeoutException will be thrown.
Int32 count = Rs232.Read(readBuffer, 0, Rs232.ReadBufferSize);
String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);
return SerialIn;
}
catch (TimeoutException) { return ""; }
}
else
{
Thread.Sleep(50);
return "";
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
public string Read()
{
return Rs232.ReadExisting();
}
public string ReadAll()
{
//TO DO
return "";
}
public void Write(string Data)
{
if (Rs232 == null)
throw new Exception("Must be connected before Write");
if (!Rs232.IsOpen)
throw new Exception("Must be opened before Write");
Rs232.Write(Data);
}
public void ClearBuffer()
{
Rs232.DiscardInBuffer();
}
private bool m_Connected;
#region IComm Members
private int m_Id;
public int Id
{
get
{
return m_Id;
}
set
{
m_Id = value;
}
}
#endregion
public override string ToString()
{
return this.ConnType.ToString();
}
#region IComm Members
#endregion
}
public interface IComm
{
ConnType ConnType
{
get;
set;
}
bool Connected
{
get;
}
int Id
{
get;
set;
}
void Connect();
void Disconnect();
void Write(string Data);
string Read();
string ReadOnByte(int Lenght, char EndChar);
String ReadBuffer();
void ClearBuffer();
string ReadAll();
event EventHandler EvtOnConnect;
event EventHandler EvtOnDisconnect;
event EventHandler<EventArgs.OnDataReceivedEventArgs> EvtOnDataReceived;
}
I hope that works for you
Are you using the serial port class?
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.aspx
How do you know that it isn't sending the character? Is it possible that the baud/word length/parity setting are off and your board is just not recognizing the character?
Also, why c#? Just seems an odd choice for hardware IO.