I'm writing a mobile application that will actually be running as a Task in ArcGIS, but my question is basically C# error handling. I'm using a while loop to loop through records and using StreamWriter to log a failed attempt to read the data. I've broken each field into its own seperate try catch so that I can write which record and which field caused the failure to the log file. Example below.
try
{
TrafficLanesCount = Convert.ToByte(ModifiedFDR.GetValue(ModifiedFDR.GetOrdinal("TRAFICLN")));
}
catch
{
sw.WriteLine(DOTNumber + " " + "TrafficLanesCount");
}
I'm saving at the end of the while loop, but if anything fails, I want to log it, skip that record, and continue on with the next record. Does anyone know a way to do this?
Instead of
sw.WriteLine(DOTNumber + " " + "TrafficLanesCount");
You could use
File.AppendAllText("path/to/log.txt", DOTNumber + " " + "TrafficLanesCount" + nvironment.NewLine);
To write the lines in realtime. This way, your logs would be persisted within every catch..
I also want to point out, that there are very mature Frameworks for Logging. For example NLog or Log4net to name two of the more popular ones.
Using the code provided, I would go with something like this:
var errorList = new List<Exception>();
foreach(var record in records)
{
try
{
try
{
TrafficLanesCount = Convert.ToByte(ModifiedFDR.GetValue(ModifiedFDR.GetOrdinal("TRAFICLN")));
}
catch
{
throw new Exception(new string(DOTNumber + " " + "TrafficLanesCount"));
}
}
catch (Exception exp)
{
errorList.Add(exp);
}
}
And afterwords, you can loop through the exceptions in the list and handle them at that point.
Related
I'm trying to read values from S7-1200 PLC using s7.net plus library. When I try to read data from datablocks it returns "WrongVarFormat" message. My code is:
using (var plc = new Plc(CpuType.S71200, "192.168.1.17", 0, 0))
{
//IP is responding
if (plc.IsAvailable)
{
ErrorCode connectionResult = plc.Open();
//Connection successful
if (connectionResult.Equals(ErrorCode.NoError))
{
//Get data
object b2 = plc.Read("DB1.DBD38");//This part always return "WrongVarFormat"
}
}
Also, I set the plc settings and i declare the datablock and values as this:
S7-1200 DB1
Also, just in case, check the PLC configuration for permissions. If the setup is not ok, the PLC will refuse any requests.
https://www.youtube.com/watch?v=tYTjNG8YL-c
Almost the entire method public object Read(string variable) is wrapped by try/catch and it always returns ErrorCode.WrongVarFormat, when any exception is hit.
public object Read(string variable)
{
...
try
{
...
}
catch
{
lastErrorCode = ErrorCode.WrongVarFormat;
lastErrorString = "Die Variable '" + variable + "' konnte nicht entschlüsselt werden!";
return lastErrorCode;
}
}
No matter, what exeception is thrown inside the try-block, the code always returns ErrorCode.WrongVarFormat and the information about the crash is lost.
As an aid in debugging, the catch can be changed to:
catch (Exception ex)
{
Console.WriteLine("Got exception {0}\n", ex.ToString());
...
The code should define its own exception class for WrongVarFormat error conditions. The catch-statement should catch only this exception and the throw-statements in the address parser should be changed to throw the WrongVarFormat-Ecxeption.
Unless you are willing to change the code of the library, you can only use a debugger to find the cause of your problem.
Make sure your plc have Get/Put allowed (under HW-config)
You cant use optimezed block access.
I am trying to localize my program but I would like error messages that are sent to the developers to appear in English. I haven't been able to find a way to make this happen since it seems that if the UI culture is set to another language when an error is thrown, it is thrown in that language. Since I did not write this program myself, and it is quite large, I think it would be impractical to go create new try catch blocks to try and set the culture back to english whenever an error occurs or might possibly occur. Currently the CurrentCulture and DefaultThreadCurrentCulture are always set to be English throughout the entire application, while the CurrentUICulture is set to the end user's language.
As I workaround, I currently have a function that has been iterating through a list of errors (using System.Resources.ResourceSets (which I assume are Windows errors, but I also need a way to find the .NET errors so I can iterate through those). It string replaces matching errors in other languages and replaces them with their English equivalents to build a large message of errors to be sent to the developers whenever the application crashes. Really, I don't have much to translate as most of the message is a server stack trace and showing where the exception was thrown. The biggest problem is translating the Inner Exception message and sometimes the main exception message since sometimes the errors thrown don't appear in the ResourceSet and sometimes use formatting items like '{0}'.
Here is the code I have so far to translate the remaining errors. I'm still working on adding regex patterns to translate errors that use things like '{0}', so if anyone has suggestions for that or better ways to do this I'd appreciate suggestions.
public static string TranslateExceptionMessageTest(string exmsg, Exception e, CultureInfo currentui)
{
CultureInfo test = Thread.CurrentThread.CurrentUICulture;
string matchingstr = "";
string newstr = exmsg;
string resourcecollection = "";
Assembly a = e.GetType().Assembly;
ResourceManager rm = new ResourceManager(a.GetName().Name, a);
ResourceSet rsOriginal = rm.GetResourceSet(currentui, true, true);
ResourceSet rsTranslated = rm.GetResourceSet(new CultureInfo("en-US"), true, true);
foreach (DictionaryEntry item in rsOriginal)
{
if (exmsg.Contains(item.Value.ToString()))
{
if (item.Key.ToString() == "Word_At") // sometimes with spanish errors this replaces words containing the letters 'en' with 'at'.
{
string newat = " " + item.Value.ToString() + " "; // this is the formatting the word 'at' appears with, in any culture I've tested.
matchingstr = " " + rsTranslated.GetString(item.Key.ToString(), false) + " ";
newstr = newstr.Replace(newat, matchingstr);
}
else
{
matchingstr = rsTranslated.GetString(item.Key.ToString(), false);
newstr = newstr.Replace(item.Value.ToString(), matchingstr);
}
}
resourcecollection = resourcecollection + Environment.NewLine + "Key: " + item.Key.ToString() + Environment.NewLine + "Value: " + item.Value.ToString();
}
return newstr; // success
}
I have also tried using the method posted here ( Exception messages in English? ) but without much luck. I still ended up with the same localized error messages. Here is the code where I know an error is being thrown but it doesn't seem like the catch block is doing anything to change the language. My ExceptionLogger class is set up the same way as in the Stackoverflow example with the addition of a line to write the error to a file. The error is being thrown at wcf.Client.Ping() (I don't care about the actual error. I'm using it to test).
private void PreloadWcfDlls(object state)
{
if (Global.Inst.ServerMode == ApplicationServerMode.Unknown)
return;
try
{
using (var wcf = ClientGrabber.GetSchemaClient(Global.Inst.ServerMode))
{
wcf.Client.Ping();
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString()); //Will display localized message
ExceptionLogger el = new ExceptionLogger(ex);
System.Threading.Thread t = new System.Threading.Thread(el.DoLog);
t.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
t.Start();
}
}
If nothing else, is there a way I can get a list of all possible .NET Framework errors in English as well as in other languages? Is there a class I can access to get these from within my program or a list elsewhere? I've tried looking at sites like unlocalize.com and finderr.net but I really don't want to have to write something to crawl through all the pages to find every possible error.
Sorry if I'm completely missing something. I'm pretty new to C# and programming in general and this problem is driving me kind of crazy!
Edit: I forgot to add that I would prefer to avoid a solutions like these where you have to be constantly changing the CurrentUICulture:
Force exceptions language in English
Prevent exception messages from being translated into the user's language?
Or solutions where you delete language packs or something on the user's computer or just set the errors to be in English when debugging (these error logs will also be sent from an end users computer in the case that the application crashes and if they are using another language we need the errors logged in English).
Also, I know I could just google the error messages or use unlocalize.com or finderr.net to translate the messages but I think the other developers might kill me if they had to do that, hah. I guess if worse comes to worst I could query the unlocalize site? Seems like a real pain though.
Here you can find a solution for the problem. To make the long story short:
try
{
System.IO.StreamReader sr=new System.IO.StreamReader(#"c:\does-not-exist");
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString()); //Will display localized message
ExceptionLogger el = new ExceptionLogger(ex);
System.Threading.Thread t = new System.Threading.Thread(el.DoLog);
t.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
t.Start();
}
Where the ExceptionLogger class looks something like:
class ExceptionLogger
{
Exception _ex;
public ExceptionLogger(Exception ex)
{
_ex = ex;
}
public void DoLog()
{
Console.WriteLine(_ex.ToString()); //Will display en-US message
}
}
The exception framework loads the error messages based on culture of current thread.
So what you can do is, catch the exception and in catch block you can make your own logger object and set its culture according to your need.
try
{
//.....Code Goes Here
}
Catch (Exception ex)
{
var eh = new ExceptionHandler("Your-Culture");
//....code goes here
}
Public class ExceptionHandler
{
//code goes on
public ExceptionHandler(string culture)
{
//set your culture here
}
}
Try this:
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
I'm working in a new place and seeing a lot of things in the code I'm not comfortably with.
I've been seeing a lot of code like this:
try
{
dAmount = double.Parse(((TextBox)control.Items[someRow].FindControl("txtControl")).Text);
}
catch
{
dAmount = 0;
}
I read stackoverflow and the like frequently and I'm aware that is not right, but I'm debating myself about the best way to handle this.
The developer obviously thought setting dAmount=0; was a good way to handle the exception, but seeing how double.Parse can only throw 3 exceptions(ArgumentNullException, FormatException, OverflowException) and if we add the NullReferenceException in case the FindControl or other object comes back null, then it seems to me I get to cover all the cracks, however the code looks kind of ugly, and I'm looking for suggestions, a better approach maybe?
This is what I came out with
try
{
dAmount = double.Parse(((TextBox)control.Items[someRow].FindControl("txtControl")).Text);
}
catch ( NullReferenceException nullRefEx )
{
dAmount = 0;
nwd.LogError("***Message: " + nullRefEx.Message + " ***Source: " + nullRefEx.Source + " ***StackTrace: " + nullRefEx.StackTrace);
}
catch ( ArgumentNullException argNullEx )
{
dAmount = 0;
nwd.LogError("***Message: " + argNullEx.Message + " ***Source: " + argNullEx.Source + " ***StackTrace: " + argNullEx.StackTrace);
}
catch ( FormatException frmEx )
{
dAmount = 0;
nwd.LogError("***Message: " + frmEx.Message + " ***Source: " + frmEx.Source + " ***StackTrace: " + frmEx.StackTrace);
}
catch ( OverflowException ovrEx)
{
dAmount = 0;
nwd.LogError("***Message: " + ovrEx.Message + " ***Source: " + ovrEx.Source + " ***StackTrace: " + ovrEx.StackTrace);
}
BTW I don't control the logging function is from another team in here, I know is kind of ugly.
What about saving the exception in a general Exception and having only one nwd.LogError call at the end? any suggestions are welcome.
You're doing exactly the same thing with all of your exceptions, which rather defeats the purpose of catching them all separately. You should be catching different exceptions if you intend to actually do something different with each type.
Your finally block will run and zero out your value even if there are no exceptions.
You shouldn't be using exceptions for control flow in the first place; you should be writing the code so that no exceptions are thrown at all if the user inputs invalid data, rather than throwing and catching an exception for a non-exceptional use-case. In this context that's as simple as using double.TryParse.
Exceptions such as null reference/null argument exceptions, overflow exceptions, etc. should pretty much never be caught at all outside of a top level method that logs any fatal exceptions before failing gracefully. These are boneheaded exceptions; if you're getting them it's a sign that you have a bug in your code that you need to fix, not a problem that you should try to sweep under the rug and continue executing your program.
You should use Double.TryParse instead.
double number;
if (Double.TryParse(value, out number))
dAmount = number;
else
dAmount=0;
This is cleaner and avoids exceptions altogether.
Don't use finally because that will always set dAmount = 0, even if an exception isn't thrown. If you want to catch a general Exception, then a single catch (Exception ex) will suffice. If you want to catch those specifically, I would do the following:
try
{
// code here
...
}
catch (Exception ex)
{
if (ex is NullReferenceException || ex is ArgumentNullException
|| ex is FormatException || ex is OverflowException)
{
// handle ex
...
return;
}
throw;
}
In your case, your best option is to probably use Double.TryParse, like so:
double amount;
if(Double.TryParse(someValue, out amount)
{
// do something with amount...
}
else
{
// handle the error condition here
}
Catch a single exception that covers all those instances. The message in the log file should distinguish which type of exception was thrown.
string s = ....;
double d = 0;
try {
d = Double.Parse(s);
} catch (Exception ex) {
//Set default value
nwd.LogError("***Message: " + ex.Message + " ***Source: " + ex.Source + "***StackTrace: " + ex.StackTrace);
}
The key the other answers are missing is that he wants to log the exception... TryParse won't tell you why it didn't parse correctly, it just returns false and 0 in the out param.
The real question here is... is zero actually special? I.e. is 0 not a valid number for a person to put into the text box? How would the rest of the program tell whether the user entered a zero, or the zero was a result of the default value being returned on parse error?
The better plan, and one I use when I am getting a value object and might fail is to use a nullable...
string s = ....;
double? d = null;
try {
d = Double.Parse(s);
} catch (Exception e) {
nwd.LogError("***Message: " + ex.Message + " ***Source: " + ex.Source + "***StackTrace: " + ex.StackTrace);
}
return d;
Now the caller knows for a fact that an error occurred when you return null (versus some "magic value"). Using "magic values" unnecessarily complicates the semantics.
Even better is to simply let the error propagate (or re-throw it) to where it can actually be handled reasonably. What part of your code currently checks for that 0 "magic value" and does something different based on it? That's where your catch should be (or, catch and log and then rethrow).
Try/Catch isn't there to control flow of your methods. If you can't redesign whole thing then I'd do something like this.
public double Parse(...)
{
double value = 0;
string text = ((TextBox)control.Items[someRow].FindControl("txtControl")).Text;
double.TryParse(text, out value);
return value;
}
I want to get line number of code which cause error. For example;
static void Main(string[] args)
{
using (SqlConnection conn = new SqlConnection(bagcum))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
conn.Open();
int n = cmd.ExecuteNonQuery();
}
}
so As we know that code doesn't work, it will throw exception Line number of code which is:
int n = cmd.ExecuteNonQuery();
So how can get that line number of using try-catch? I tried using a StackTrace class but it gives line number as 0:
static void Main(string[] args)
{
try
{
using (SqlConnection conn = new SqlConnection(bagcum))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "DONTINSERT into GIVEMEERROR(CamNo,Statu) values (" + 23 + "," + 0 + ")";
conn.Open();
int n = cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}
}
OUTPUT:
Line:0
Update:
Usually error line of code is 22 so I have to get that number.
Thanks
Try this simple hack instead:
First Add this (extension) class to your namespace(most be toplevel class):
public static class ExceptionHelper
{
public static int LineNumber(this Exception e)
{
int linenum = 0;
try
{
//linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(":line") + 5));
//For Localized Visual Studio ... In other languages stack trace doesn't end with ":Line 12"
linenum = Convert.ToInt32(e.StackTrace.Substring(e.StackTrace.LastIndexOf(' ')));
}
catch
{
//Stack trace is not available!
}
return linenum;
}
}
And its done!Use LineNumber method whenever you need it:
try
{
//Do your code here
}
catch (Exception e)
{
int linenum = e.LineNumber();
}
try this
To get the line numbers in the StackTrace, you need to have the correct debug information (PDB files) alongside your dlls/exes. To generate the the debug information, set the option in Project Properties -> Build -> Advanced -> Debug Info:
Setting it to full should suffice (see the MSDN docs for what the other options do). Debug info (ie. PDB files) are generated for Debug build configurations by default, but can also be generated for Release build configurations.
Generating PDBs for release builds enables you to ship you code without the PDBs, but to drop the PDBs next to the dlls if you need line numbers (or even to attach a remote debugger). One thing to note is that in a release build, the line numbers may not be entirely correct due to optimisations made by the compiler or the JIT compiler (this is especially so if the line numbers show as 0).
The problem is that you're trying to get the line number of the first frame of the exception:
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
However, the exception does not originate in the line you write ExecuteNonQuery, but somewhere within that function, possibly multiple stack frames (i.e. nested function calls) deeper. So the first frame (which you explicitly retrieve using GetFrame(0)) is somewhere inside Microsoft's code (most likely System.Data.dll) for which you don't have any debugging symbols.
Write out the complete exception stacktrace in your function to see what I mean:
try
{
// your code ...
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Short of parsing the stacktrace (i.e. ex.StackTrace) there is no reliable why to get the linenumber of the "ExecuteNonQuery()" invocation. I would especially not try to count the stackframes up the stack where your call to ExecuteNonQuery() happens.
I wonder however, what you need the sole linenumber for, why not just log/print/whatever the complete stacktrace instead. At least for diagnostics reasons that is much more useful anyway.
You might get 0 in result if you don't initialize StackTrace to include fileinfo.
Try this
try
{
//code
}
catch (Exception e)
{
var lineNumber = new System.Diagnostics.StackTrace(e, true).GetFrame(0).GetFileLineNumber();
}
This worked for me.
You can use the System.Diagnostics.StackTrace class as below:
public void MethodName()
{
try
{
throw new Exception();
}
catch (Exception ex)
{
// Get stack trace for the exception with source file information
var trace = new StackTrace(ex, true);
// Get the top stack frame
var frame = trace.GetFrame(0);
// Get the line number from the stack frame
var line = frame.GetFileLineNumber();
}
}
Here's a rather easy way to get a bunch of info from the Exception object: Just add code like this to any potentially exception-throwing methods:
catch (Exception ex)
{
String exDetail = String.Format(ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
MessageBox.Show(exDetail);
}
The information you get will often be more specific, especially as regards line numbers of where problems are occurring, than you would otherwise see.
You may have noted that the String.Format() uses a constant, namely "ExceptionFormatString". This is a good practice, so that if you want to change it, after adding the above code to 40-eleven methods, you can just change it one place. Anyway, here it is:
public static readonly String ExceptionFormatString = "Exception message: {0}{1}Exception Source: {2}{1}Exception StackTrace: {3}{1}";
Happy Debugging!
To get line numbers, you need your application to be in Debug mode or include the debug symbols in the same folder (the .pdb file) for line numbers to appear. You code as posted should then work.
the following code exception log handler method is works fine :
in catch :
catch (Exception ex)
{
CommonTools.vAddToLog(ex, EmpID, ErrorCodes.UnDefined);
Response.Redirect("~/ErrorPage.aspx");
}
in AddToLog method :
string _exMsgErr = string.Empty;
var frame = oStackTrace.FrameCount > 1 ? oStackTrace.GetFrame(1) : oStackTrace.GetFrame(0);
if (oException.GetType() == typeof(JOVALException))
{
JOVALException _JOVALEx = (JOVALException)oException;
_exMsgErr = _JOVALEx.Message;
}
else
{
_exMsgErr = oException.Message;
}
ErrorLog oError = new ErrorLog(frame.GetMethod().Name, (string)frame.GetFileName(), (int)frame.GetFileLineNumber(), sCustomErrorMessage == string.Empty ? _exMsgErr : sCustomErrorMessage, sUserID, oErrCode);
//Cont. your code of log file
Finally the xml log file looks like this :
<ErrorLog>
<MethodName>FillRolesDDLs</MethodName>
<FileName>
F:\Projects\ERP\ERP\Pages\SystemSettings\Roles.aspx.cs
</FileName>
<LineNumber>61</LineNumber>
<ErrorMesssage>
The given DataRow is not in the current DataRowCollection.
</ErrorMesssage>
<UserID>1</UserID>
<ErrCode>UnDefined</ErrCode>
<Time>15/03/2015 16:23:21.976</Time>
</ErrorLog>
In .NET 4.5 you can use the ExceptionDispatchInfo to rethrow your exceptions instead of the classic throw;(make sure the PDB files are there or no line numbers will be displayed):
static void A()
{
try
{
throw new Exception("A");
}
catch (Exception e)
{
ExceptionDispatchInfo.Capture(e).Throw();
}
}
Source: blogpost.
PDB files don't decrease performance on Windows.
Copy the entire stack trace in to a string or stringbuilder by using try/catch that can throw, see the below example
try
{
//Do some programming
}
catch(Exception ex)
{
//Catch the exception and assign the stack trace
StackTrace = ex;
}
The output will be
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Program.Run() in C:\Console Application1\Program.cs:line 37
at Program.Main(String[] args) in C:\Console Application1\Program.cs:line 45
The first line shows the type of the exception and the message. The second line shows the file, function and line number where the exception was thrown
How would i go about to do this?
protected void Page_Load(object sender, EventArgs e)
{
try
{
doSomething();
}
catch (Exception ex)
{
// Here i would like to know that the page is "Problem.aspx"
// and that it was caused from the doSomething() function
}
}
private void doSomething()
{
logToSomething();
}
Exception object has a stack trace property, which tells you exactly where the error took place.
Also, check out Microsoft Enterprise Library (more specifically the Logging Block).
The logged errors provide a stack trace, among other things, letting you know exactly where the error occurred.
I'm using this little class to log errors, have a look on how i get the page and the function(Stacktrace):
public static class ErrorLog
{
public static void WriteError(Exception ex)
{
try {
string path = "~/error/logs/" + System.DateTime.Now.ToString("dd-MM-yyyy") + ".txt";
if ((!System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(path)))) {
System.IO.File.Create(System.Web.HttpContext.Current.Server.MapPath(path)).Close();
}
using (System.IO.StreamWriter w = System.IO.File.AppendText(System.Web.HttpContext.Current.Server.MapPath(path))) {
w.WriteLine(System.Environment.NewLine + "Log Entry : {0}", System.DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture));
var page = VirtualPathUtility.GetFileName(HttpContext.Current.Request.Url.AbsolutePath);
w.WriteLine("Error in: " + page);
string message = "Message: " + ex.Message;
w.WriteLine(message);
string stack = "StackTrace: " + ex.StackTrace;
w.WriteLine(stack);
w.WriteLine("__________________________");
w.Flush();
w.Close();
}
} catch (Exception writeLogException) {
try {
WriteError(writeLogException);
} catch (Exception innerEx) {
//ignore
}
}
}
}
It's entirely sufficient for me.
Note: converted from VB.NET, hence untested
You can determine all of that by parsing the Exception message.
Look at your message and use a regex to extract the information you need.
Another option that you may want to look into is ELMAH ( Error Logging Modules and Handlers for ASP.NET ) http://code.google.com/p/elmah/ . I guess it really depends on what your specific needs are.
Use log4net, for logging the error messages. For help look at these article 1 and article 2.
Whatever logging method you use, do something like this.(Hand typed may not compile)
try
{
DoignStuff();
}
catch( Exception ex)
{
Trace.WriteLine( "Exception in <Page Name> while calling DoingStuff() Ex:"+ ex.ToString() );
}
It will start with the page name & method (which is redundant, but makes life easier)
then it will convert the EX to a string which shows call stack and all kinds fo other good stuff and put it in the log file
Note: you have to Type the name of the page in the place of <Page Name> .
Log4Net and Elmah are great to make life easier too.