In a C# program, I have an error check that gets repeated a lot:
try
{
File.Move(searchfolder + question1 +"_"+ filestring +".txt",
searchfolder + question1 +".txt");
}
catch (Exception ex)
{
File.AppendAllText(adminfolder + question1 +"_l.txt", "!");
side.Value = Convert.ToString(ex) + "[Check-In error at "
+ Convert.ToString(MYLINE) +"] "+ side.Value;
}
MYLINE is some number, and MYLINE is the only thing that changes across my program.
So a normal C++ #define macro would make this much simpler to work with (I would just write the full "#define CHECKIN(MYLINE) ..." once at the top of the program).
How would a pro deal with this in C#?
...and MYLINE is the only thing that changes across my program. So a normal C++ #define macro would make this much simpler to work with
Well, perhaps, but since C# doesn't have a concept of macros... just use a method:
static class FileMover
{
public static void MoveMyFile(string myline)
{
// your existing code here
}
}
On a side note, there is glaring problem in your code. In your catch block you call File.AppendAllText()... which, of course, can throw an exception as well. You need to account for that.
Related
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.
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've written a simple (console)script in C# that recursively deletes files and folders in the given parameter ex: delete_folder.exe "C:\test"
I use this tiny piece of code during an uninstall to delete the remaining files after the uninstall.
The code on itself works fine, but I receive the error: System.IO.IOException: The process cannot access the file 'C:\test\test2' because it is being used by another process.
Just before this error the uninstaller stops and deletes a couple of services (created by the installer)
It seems to me that Windows still uses the folder test2. So my question is: How to check if a folder is in use by another process and how to stop that process from being there, to be able to delete the remaining folders.
The console application looks like this:
class Program
{
public static void log(string t)
{
File.AppendAllText("C:\\testlog.txt", DateTime.Now.ToString() + "----" + t + "\r\n");
}
static void Main(string[] args)
{
try
{
string path = args[0];
if (Directory.Exists(path) == true)
{
Directory.Delete(path, true);
}
else
{
Console.WriteLine("Dir not found!");
}
}
catch (Exception ex)
{
log(ex.ToString());
}
}
}
A try...catch might sound not too elegant (actually, basing the normal flow of an algorithm on this statement is inadvisable in most of the cases), but seems the only way through here. Bear in mind that there is no System.IO (direct) property telling whether an element is in use; and thus relying on this is the usual solution for this kind of problems (post about file in use). Sample code:
foreach (string dir in System.IO.Directory.GetDirectories(rootDirectory))
{
try
{
System.IO.Directory.Delete(dir);
}
catch
{
//There was a problem. Exit the loop?
}
}
I'm creating a Class library where I can import the DLL in later projects and just call the below to send a DirectMessage to Twitter user. It works if I include the code directly in the Form1 class but I dont want that I want to be able to do something like in VB:
Dim dm as New SendDM
dm.SendDirectMessage(user, message)
and it go. Any ideas? Im not that familiar with C# so should I make it public? Put it in it's own class file like SendDM.cs or what?
private void SendDM(string user, string message)
{
if (message.Length == 0)
{
MessageBox.Show("Your tweet must be at least 1 character long!");
return;
}
try
{
// URL-encode the tweet...
string tweet = HttpUtility.UrlEncode(message);
// And send it off...
string xml = _oAuth.oAuthWebRequest(
oAuthTwitter.Method.POST,
"http://api.twitter.com/1/direct_messages/new.xml",
"?user=" + user + "&text=" + message);
}
catch (Exception ex)
{
MessageBox.Show("An error occurred while posting your tweet:\n\n" + ex.Message);
return;
}
message = String.Empty;
}
Yes you can. Create a "Class Library" project. Insert your code and compile it.
from a class library you should not use MessageBoxe to notify exceptions or validate input parameters, just throw the exception from the catch instead of return and throw ArgumentOutOfRangeException if input parameter doesn't validate.
Said this, you should have a public class SendDM and inside it a public method SendDirectMessage if you wish to use your VB code shown above to send the message.
Also, you do not need to reset message to String.Empty at the end of the SendDirectMessage method.
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.