I have an application talking to a USB-GPS. It’s working as a charm if nothing out of the ordinary happnes. But I have a big problem. If the USB gets pulled out, my program (some times) crashes. I have Try/Catch where I need them but this IOExeption doesn’t get caught. I just get "The device does not recognize the command" and the program stops. Here is the code that starts the port:
public LatLongFromGPS(Form1 parent)
{
this.parent = parent;
String port;
this.SPort = new SerialPort(port, 4800);
this.SPort.ReadTimeout = 500;
this.SPort.DataReceived += new SerialDataReceivedEventHandler(dataReceived);
}
public bool checkIfPortsOpen()
{
return (this.SPort.IsOpen);
}
public void openPort()
{
try
{
if (!this.SPort.IsOpen)
{
this.SPort.Open();
}
}
catch(Exception ex)
{
parent.LoggIt.WriteLogg("OPENPORT " + ex.ToString(), Logger.LoggType.Debug);
}
}
public void dataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (SPort.IsOpen)
{
String GPGGAString;
Thread.CurrentThread.Join(200);
buffert = new char[this.SPort.BytesToRead];
this.SPort.Read(buffert, 0, buffert.Length);
GPGGAString = findStringFromGPS();
if (GPGGAString != null)
{
getLatitudefromString(GPGGAString);
getLongitudefromString(GPGGAString);
getTimeFromString(GPGGAString);
this.newData = true;
}
}
}
catch(Exception ex)
{
parent.LoggIt.WriteLogg("GPSERROR " + ex.ToString(), Logger.LoggType.Debug);
}
}
Then I have this in a Timer to check the info
if (this.LatLong.newDataReceived())
{
//DOING STUFF
}
if (!this.LatLong.checkIfPortsOpen())
this.LatLong.openPort();
Anyone have any suggestions how to stop the crashes?
[EDIT] The stack:
at System.IO.Ports.InternalResources.WinIOError(Int32, System.String)
at System.IO.Ports.InternalResources.WinIOError()
at System.IO.Ports.SerialStream.Dispose(Boolean)
at System.IO.Ports.SerialStream.Finalize()
I'm not entirely sure if it applies here, but there are mechanisms to catch overall crashes at the appdomain level -
http://msdn.microsoft.com/en-GB/library/system.appdomain.unhandledexception.aspx
(not the section on other events, e.g. ThreadException - these may need their own handlers depending on the situation)
Although not a best practice, top-level exception handling might solve your problem. See http://richnewman.wordpress.com/2007/04/07/top-level-exception-handling-in-windows-forms-applications-%E2%80%93-code-listing-1/ for an example.
Related
I have a c# windows service which is doing various tasks. Its working perfectly on my local system but as soon as I start it on my product server, its doesn't perform a particular task on it.
This is how my service is structured:
public static void Execute()
{
try
{
// .... some work ....
foreach (DataRow dr in dt.Rows)
{
string cc = dr["ccode"].ToString();
Task objTask = new Task(delegate { RequestForEachCustomer(cc); });
objTask.Start();
}
}
catch (Exception ex)
{
// Logging in DB + Text File
}
}
public static void RequestForEachCustomer(object cc)
{
try
{
// .... some work ....
foreach (DataRow dr in dt.Rows)
{
WriteLog("RequestForEachCustomer - Before Task");
Task objTask = new Task(delegate { RequestProcessing(dr); });
objTask.Start();
WriteLog("RequestForEachCustomer - After Task");
}
}
catch (Exception ex)
{
// Logging in DB + Text File
}
}
public static void RequestProcessing(object dr)
{
try
{
WriteLog("Inside RequestProcessing");
// .... some work ....
}
catch (Exception ex)
{
// Logging in DB + Text File
}
}
Now what happens on the production server is that it logs the last entry in RequestForEachCustomer which is "RequestForEachCustomer - After Task" but it doesn't log the entry from RequestProcessing which mean the task is not starting at all. There are no exceptions in either database or text file.
There are no events logged in window's event viewer either. Also the service keeps working (if I insert another record in database, its processed by the service immediately so the service isn't stuck either. It just doesn't seem to process RequestProcessing task.)
I am baffled by this and it would be great if someone could point out the mistake I am making. Oh, btw did I forgot to mention that this service was working perfectly few days ago on the server and it is still working fine on my local PC.
EDIT :
WriteLog :
public static void WriteErrorLog(string Message)
{
StreamWriter sw = null;
try
{
lock (locker)
{
sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\LogFile.txt", true);
sw.WriteLine(DateTime.Now.ToString() + ": " + Message);
sw.Flush();
sw.Close();
}
}
catch (Exception excep)
{
try
{
// .... Inserting ErrorLog in DB ....
}
catch
{
throw excep;
}
throw excep;
}
}
I have also logged an entry on OnStop() something like "Service Stopped" and its logs every time I stop my service so the problem couldn't exist in WriteLog function.
I suggest you refactor your code as in this MSDN example. What bother me in your code is, you never wait for tasks to finish anywhere.
The following example starts 10 tasks, each of which is passed an index as a state object. Tasks with an index from two to five throw exceptions. The call to the WaitAll method wraps all exceptions in an AggregateException object and propagates it to the calling thread.
Source : Task.WaitAll Method (Task[])
This line from example might be of some importance :
Task.WaitAll(tasks.ToArray());
Im working on an EConnect integration Windows form app in C#. Im having a lot of trouble testing my connection string. Basically I give the user the option to change the connection string so I want to be able to test it. As far as I know EConnect doesnt have any built in functions that test the connection so I'm writing a pretty crude function to do it myself. Just for everyones information the connection string consists of a server name that the GP databases are located on and a database name.
The particulars of the actual test function I dont think are that important but the main issue is within that function I call an eConnect method called getEntity, this method uses the connection string and if the connection string is right it will pull information. If the database name is wrong the getEntity method will return an eConnect exception which is easy enough to catch, however if the server name is wrong the getEntity method will just spin and my app gets stuck.
Im trying to write something where I can possibly run my test function asynchronously and simultaneously check for a timeout or the econnect exception. This is where I get stuck, I cant for the life of me get it to work. Here is the first thing I tried (this is in my TestConnection method):
task = Task.Factory.StartNew(() => requester.GetEntity(GPCongfigSettings.GPConnectionString, myXmlDocument.OuterXml), token);
try
{
if (!task.Wait(timeOut, token))
{
Console.WriteLine("The server name is incorrect - task timed out");
return false;
}
}
catch (ThreadInterruptedException)
{
return false;
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is eConnectException) // This we know how to handle.
{
Console.WriteLine("Incorrect Database Name! -- " + x.Message);
return false;
}
return false; // Let anything else stop the application.
});
}
This would catch the cases where the server was wrong and if my econnect method would just time out. But it never caught the eConnect exception, Visual Studio would break the app and tell me I had an unhandled exception.
Here is what Im trying now, this is the full class I have for my form. Here I'm trying to use IAsyncResult and using a WaitHandle to check to see if the function completes or times out. This seems to work sometimes, it works for a correct string and for when the database is wrong, and sometimes it works for when the server is wrong, but once I test for a wrong server name it doesnt work correctly for anything else anymore. Is there something I'm missing or is there a better way to run the getentity method in TestGPConnection and check to see if it hasnt completed after a certain time period and if it hasnt kill that method and have the user reenter a server name?
public partial class UpdateGPConnection : Form
{
Task task;
AsyncCallback cb;
public delegate string startProcessToCall();
startProcessToCall sp2c;
public UpdateGPConnection()
{
InitializeComponent();
this.txtDatasourceName.Text = ConfigurationManager.AppSettings.Get("GPDataServer");
this.txtDatabaseName.Text = ConfigurationManager.AppSettings.Get("GPDatabase");
cb = new AsyncCallback(startProcessCallback);
sp2c = new startProcessToCall(TestGPConnection);
}
public void startProcessCallback(IAsyncResult iar)
{
startProcessToCall mc = (startProcessToCall)iar.AsyncState;
bool result = mc.EndInvoke(iar);
Console.WriteLine("Function value = {0}", result);
}
private void btnUpdate_Click(object sender, EventArgs e)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings["GPDataServer"].Value = txtDatasourceName.Text.ToUpper();
config.AppSettings.Settings["GPDatabase"].Value = txtDatabaseName.Text.ToUpper();
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
GPCongfigSettings.GPConnectionString = #"data source=" + txtDatasourceName.Text.ToUpper() + ";initial catalog=" + txtDatabaseName.Text.ToUpper() + ";integrated security=SSPI;persist security info=False;packet size=4096";
IAsyncResult asyncResult = null;
asyncResult = sp2c.BeginInvoke(cb, null);
timer1.Enabled = true;
Thread.Sleep(0);
bool test = asyncResult.AsyncWaitHandle.WaitOne(15000);
if (test)
{
try
{
string testResult = sp2c.EndInvoke(asyncResult);
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
bool result = asyncResult.IsCompleted;
asyncResult.AsyncWaitHandle.Close();
this.Close();
}
public string TestGPConnection()
{
eConnectMethods requester = new eConnectMethods();
try
{
// Create an eConnect document type object
eConnectType myEConnectType = new eConnectType();
// Create a RQeConnectOutType schema object
RQeConnectOutType myReqType = new RQeConnectOutType();
// Create an eConnectOut XML node object
eConnectOut myeConnectOut = new eConnectOut();
// Populate the eConnectOut XML node elements
myeConnectOut.ACTION = 1;
myeConnectOut.DOCTYPE = "GL_Accounts";
myeConnectOut.OUTPUTTYPE = 2;
myeConnectOut.FORLIST = 1;
myeConnectOut.WhereClause = "(ACTNUMST = '99-9999-99-999')";
// Add the eConnectOut XML node object to the RQeConnectOutType schema object
myReqType.eConnectOut = myeConnectOut;
// Add the RQeConnectOutType schema object to the eConnect document object
RQeConnectOutType[] myReqOutType = { myReqType };
myEConnectType.RQeConnectOutType = myReqOutType;
// Serialize the eConnect document object to a memory stream
MemoryStream myMemStream = new MemoryStream();
XmlSerializer mySerializer = new XmlSerializer(myEConnectType.GetType());
mySerializer.Serialize(myMemStream, myEConnectType);
myMemStream.Position = 0;
// Load the serialized eConnect document object into an XML document object
XmlTextReader xmlreader = new XmlTextReader(myMemStream);
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load(xmlreader);
string reqDoc = requester.GetEntity(GPCongfigSettings.GPConnectionString, myXmlDocument.OuterXml);
return "Correct Connection";
}
catch (eConnectException exc)
{
Console.WriteLine(exc.Message);
return "eConnect Excpetion";
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return "Excpetion";
}
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
You are not handling the eConnectException. You are showing a message in the Console and then essentially rethrowing the exception by returning false.
If you do handle an exception then you should return true to avoid rethrowing it:
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is eConnectException) // This we know how to handle.
{
Console.WriteLine("Incorrect Database Name! -- " + x.Message);
}
return x is eConnectException; //rethrow anything that is not an eConnectException
});
}
Basically I am ting to catch any exception off a block of code, and fire said code one.
try {
CODE
catch (Exception e)
{
DO THIS ONCE
}
finally
{
CODE
}
In Depth
So I have been creating a TCP/SOCKET Server. Which can work with multiple clients. And send/recite (I/O) Data. It works well, and has been for a long time now. But I have found in my console that it says this:
This is bad because if it thinks the user disconnected twice it can create many problems. The way I know if a user has disconnected is by sending data to them every 200ms. And if there is a error then print they disconnected remove them from the client list, and disconnect there stream/tcp.
static bool currentlyUsing;
private static void PingClient(Object o)
{
if (!currentlyUsing)
{
if (clientsConnected.Count != 0)
{
foreach (Client c in clientsConnected)
{
try
{
c.tcp.Client.Blocking = false;
c.tcp.Client.Send(new byte[1], 0, 0);
}
catch (Exception e)
{
currentlyUsing = true;
Console.WriteLine("[INFO] Client Dissconnected: IP:" + c.ip + " PORT:" + c.port.ToString() + " Reason:" + e.Message);
clientsConnected.Remove(c);
c.tcp.Close();
break;
}
finally
{
currentlyUsing = false;
}
GC.Collect();
}
}
}
Is there a way to make it so it catches it only once, or catches it multiple times but only fires the code I want once?
If I understand your question correctly: you want to try to run the code on each iteration of the foreach block, and always run the finally code for each iteration, but only run the catch code once?
If so:
Before the foreach block, define:
bool caught = false;
And then after:
catch (Exception e)
{
if (caught == false)
{
caught = true;
...
}
}
I was making multiple timers. So it overlapped.
I'm trying to write bot for irc channel, which will read messages from channel, recognize if they are commands to him and do some actions depends on command which was send.
I've choose ircDotNet because it was the only library that contains some examples how to use it, but they are actually very outdated, only half of them works. My lack of experience in C# and in programming at all don't allows me to understand stuff without good examples :(
So what my program does now:
logs in to server using password
joins channel
log-outs (very buggy)
I cant capture and send any messages from and to a channel and i cant log-out instantly.
Global classes that used for login and IrcClient class exemplar used everywhere in events
public IrcRegistrationInfo irc_iri
{
get
{
return new IrcUserRegistrationInfo()
{
NickName = "jsBot",
UserName = "jsBot",
RealName = "jsBot",
Password = "oauth:p4$$w0rdH3Re48324729214812489"
};
}
}
public IrcClient gIrcClient = new IrcClient();
Also all current events:
private void Form1_Load(object sender, EventArgs e)
{
try
{
gIrcClient.Connected += ircClient_Connected;
gIrcClient.Disconnected += gIrcClient_Disconnected;
gIrcClient.FloodPreventer = new IrcStandardFloodPreventer(1, 10000);
}
catch (Exception ex) { MessageBox.Show(ex.ToString());}
}
Login button code:
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
if (!gIrcClient.IsConnected)
{
button1.Text = "Connecting...";
gIrcClient.Connect("irc.twitch.tv", 6667, false, irc_iri);
}
else
{
button1.Text = "Disconnecting...";
gIrcClient.Quit(5000, "bye");
}
}
Logic is: program checks if ircClient connected or not, and do some action. Then after that action appropriate event will raise, enable that button again. But that Quit function works very slow or don't works at all, bot will stay at channel until i don't close my program (maybe i need to dispose ircclient?)
Connect and disconnect events. In connect event, bot will join channel. Bot appears at channel after ~30 seconds after i press connect button, but connected event raised after 2-3 seconds. And same for disconnect - disconnect event raises quickly, but bot stays on channel for much longer time (about 120 seconds).
void ircClient_Connected(object sender, EventArgs e)
{
try
{
if (button1.InvokeRequired)
{
MethodInvoker del = delegate {
button1.Text = "Disconnect";
button1.Enabled = true; };
button1.Invoke(del);
}
else
{
button1.Text = "Disconnect";
button1.Enabled = true;
}
gIrcClient.Channels.Join("#my_channel");
gIrcClient.LocalUser.JoinedChannel += LocalUser_JoinedChannel;
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
void gIrcClient_Disconnected(object sender, EventArgs e)
{
if (!gIrcClient.IsConnected)
{
try
{
if (button1.InvokeRequired)
{
MethodInvoker del = delegate
{
button1.Text = "Connect";
button1.Enabled = true;
};
button1.Invoke(del);
}
else
{
button1.Text = "Connect";
button1.Enabled = true;
}
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
else gIrcClient.Disconnect();
}
Join channel and message received events. They are never raising, have no idea why.
void LocalUser_JoinedChannel(object sender, IrcChannelEventArgs e)
{
try
{
gIrcClient.Channels[0].MessageReceived += Form1_MessageReceived;
gIrcClient.LocalUser.SendMessage(e.Channel, "test");
MessageBox.Show(gIrcClient.Channels[0].Users[0].User.NickName);
MessageBox.Show("bot_join_channel_event_raised");
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
void Form1_MessageReceived(object sender, IrcMessageEventArgs e)
{
try
{
if (e.Text.Equals("asd"))
gIrcClient.LocalUser.SendMessage(e.Targets, "received");
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
}
So main question is: how do i catch messages from channel and how do i send message to channel? I would appreciate any examples. You can find all code in one piece here: http://pastebin.com/TBkfL3Vq
Thanks
You try to join channel before adding an event.
gIrcClient.Channels.Join("#my_channel");
gIrcClient.LocalUser.JoinedChannel += LocalUser_JoinedChannel;
My suggestion is try adding event first like this:
gIrcClient.LocalUser.JoinedChannel += LocalUser_JoinedChannel;
gIrcClient.Channels.Join("#my_channel");
There is a bug in the IRC.NET library and twitch.tv is using a non-standard message reply that is tripping up IRC.NET.
I have created a bug here describing it. But basically twitch sends "Welcome, GLHF!" as the RPL_WELCOME message. The IRC RFC describes the format of the message to be "Welcome to the Internet Relay Network !#".
IRC.NET parses GLHF out of the welcome message as your nick name, which is used for things like firing the JoinedChannel and MessageRecieved events.
My solution is to download the source code and to comment out where it sets the nick name when receiving the RPL_WELCOME message. It sets the Nickname correctly from the IrcRegistrationInfo passed into the IrcClient constructor and doesn't need to be parsed from the welcome message from twitch. Not sure if this is the case for other IRC servers.
The function is called ProcessMessageReplyWelcome in IrcClientMessageProcessing.cs:
/// <summary>
/// Process RPL_WELCOME responses from the server.
/// </summary>
/// <param name="message">The message received from the server.</param>
[MessageProcessor("001")]
protected void ProcessMessageReplyWelcome(IrcMessage message)
{
Debug.Assert(message.Parameters[0] != null);
Debug.Assert(message.Parameters[1] != null);
this.WelcomeMessage = message.Parameters[1];
// Extract nick name, user name, and host name from welcome message. Use fallback info if not present.
var nickNameIdMatch = Regex.Match(this.WelcomeMessage.Split(' ').Last(), regexNickNameId);
//this.localUser.NickName = nickNameIdMatch.Groups["nick"].GetValue() ?? this.localUser.NickName;
this.localUser.UserName = nickNameIdMatch.Groups["user"].GetValue() ?? this.localUser.UserName;
this.localUser.HostName = nickNameIdMatch.Groups["host"].GetValue() ?? this.localUser.HostName;
this.isRegistered = true;
OnRegistered(new EventArgs());
}
A more involved solution might be to refine the nick name Regex so it does not match on GLHF!, which I think is not a valid nickname.
IRC.NET uses case sensitive string comparisons for finding users by nickname. So the value you pass into the IrcRegistrationInfo for the nickname must match the casing that twitch uses in messages pertaining to you. Which is all lowercase.
I want to send a message from a server to all clients. There are 0-* clients. The server may or may not be running when a client is loaded. The functionality here works how I want it. I am trying to figure out if this can be done without Thread.Sleep()? Also note that the clients and the server are each in independant processes.
Server Portion
class NamedEventsServer
{
internal static void Main()
{
const string ewhName = "StickyNoteEwh";
EventWaitHandle ewh = null;
bool doesNotExist = false;
bool wasCreated;
// Attempt to open the named event.
try
{
ewh = EventWaitHandle.OpenExisting(ewhName);
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Named event does not exist.");
doesNotExist = true;
}
if (doesNotExist)
{
// The event does not exist, so create it.
ewh = new EventWaitHandle(true,
EventResetMode.ManualReset,
ewhName,
out wasCreated);
if (wasCreated)
{
Console.WriteLine("Created the named event.");
}
else
{
Console.WriteLine("Unable to create the event.");
return;
}
}
ewh.Set();
Thread.Sleep(1000);//wait one second...giving threads enough time to all respond. Then stop triggering the event.
ewh.Reset();
//exit
}
}
Client Portion
class NamedEventsClient
{
internal static void Main()
{
const string ewhName = "StickyNoteEwh";
while (true)
{
EventWaitHandle ewh = null;
bool doesNotExist = false;
bool wasCreated;
// Attempt to open the named event.
try
{
ewh = EventWaitHandle.OpenExisting(ewhName);
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Named event does not exist.");
doesNotExist = true;
}
if (doesNotExist)
{
// The event does not exist, so create it.
ewh = new EventWaitHandle(false,
EventResetMode.ManualReset,
ewhName,
out wasCreated);
if (wasCreated)
{
Console.WriteLine("Created the named event.");
}
else
{
Console.WriteLine("Unable to create the event.");
return;
}
}
Console.WriteLine("Wait on the event.");
ewh.WaitOne();
Console.WriteLine("Event was signaled.");
//Console.WriteLine("Press the Enter key exit.");
Thread.Sleep(1000);
//Console.ReadLine();
}
}
}
I guess it depends whether you're certain all clients are going to get their time-slice within on second. It sounds reasonable, but under extreme stress some clients might miss it. How crucial is that?
Anyway, I think this is exactly the kind of thing you should use ZeroMQ for. It's light-weight, and takes care of all the potential bugs for you.