i have a code like this:
private void Load_Button_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
if (dialog.ShowDialog()==DialogResult.OK){
MessageBox.Show(dialog.FileName,"My Application", MessageBoxButtons.OK,MessageBoxIcon.Asterisk);
string s;
s=".bmp";
if (dialog.FileName.Substring(dialog.FileName.LastIndexOf('.')).Equals(s))
{
picBox_1.Load(dialog.FileName);
BitmapFile = new Bitmap(dialog.FileName.ToString());
}
else {
MessageBox.Show("Not a BMP file!");
}
}
}
so, load image. and have an error in this:
private void Save_Button_Click(object sender, EventArgs e)
{
SaveFileDialog dialog = new SaveFileDialog();
try
{
if (picBox_1.Image != null)
{
if (dialog.ShowDialog() == DialogResult.OK)
{
MessageBox.Show(dialog.FileName, "My Application", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
string s;
s = ".bmp";
if (dialog.FileName.Substring(dialog.FileName.LastIndexOf('.')).Equals(s))
{
picBox_1.Image.Save(dialog.FileName.ToString());
//BitmapFile.Dispose();
}
else
{
MessageBox.Show("Not a BMP file!");
}
}
}
else
{
MessageBox.Show("My PicBox is empty!");
}
}
catch (Exception) { MessageBox.Show("Cannot save file, error!"); }
}
this is general GDI error. I suppose, that i can't write to file (not enough rights, maybe). how can i improve this error?
you should catch the exceptions properly, not with a MessageBox which tells you nothing about the exact exception thrown!
at minimum your catch block should look like this:
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
and I say at minimum because you should in fact log the exception somewhere, using a logging framework like NLog or Log4Net and dump stack trace and other details. You are not even able to tell the excact type of Exception if you show a message with a static string and not the details of the actual exception.
You should only catch specific exceptions that you intend to handle or recover from, and log the details. Never catch Exception as you would potentially be masking bigger issues with your server if they occur.
Unexpected exceptions should bubble up so that the cause can quickly be identified when they occur.
See here for Best Practices for Handling Exceptions.
You're eating the exception and losing all the juicy detail. Try changing your catch block to something like this to see what's going on:
catch (Exception ex)
{
MessageBox.Show(this, ex.ToString(), "Error Saving Image", MessageBoxIcons.Error);
}
Also, consider implementing some logging (to the event viewer and/or text file. This will allow you to have a simple message box, but with all the juicy detail put somewhere useful to fetch after the event.
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "Error Saving Image", MessageBoxIcon.Error);
// _logger is a private field on this class in this case.
_logger.Log(ex, string.Format("Saving image to {0}", dialog.Filename))
}
You could look at Log4net amongst other things for the actual logging, but at the very least write a class to write exception detail to the event viewer.
Related
I have an exception occurred when the Database connection failed in a Class. The problem is how do I notify my Main Window that this exception is caught and show a message box to notify my user?
Thanks
Use the Try ... Catch clause like this:
try
{
// The code that could generate an exception
}
catch(Exception ex)
{
MessageBox.Show("Error: " ex.Message);
}
Or if you're using SQL-Server connection, use it like this:
try
{
// The code that could generate an exception
}
catch(SqlException ex)
{
MessageBox.Show("SQL Error: " ex.Message);
}
Thanks. I may have not make my question clearly. I mean this exception
is occurred in one class, but the message box should be show in an
other windows class. So how do I communicate and show this error?
From your clarification in one of the comments:
So if you have class TestClass.cs with method Test in it.
public void Test()
{
//if you want to throw an exception defined by your business logic
if(someCondition == false)
throw CustomException();
//if you have exception in the code
int a = 5;
int b =0;
//here you will be thrown an exception can't divide by 0.
int c = a/b;
}
Your winform Button Click or whatever
public void Button_Click1(object sender, EventArgs e)
{
try
{
TestClass cl = new TestClass();
cl.Test();
}
catch(CustomException custEx)
{
//this for your Bussines logic exception
//write your message
}
catch(DivideByZeroException div)
{
//this for divide by zero exception
//write message
}
//you can catch all other exception like this but I don't advice you to do that
catch(Exception ex)
{
//for this to working properly, this catch should be under all of others(last priority)
}
}
The title is a tad confusing, so hopefully I can explain it a tad better here. I want to change the title of the MessageBox that pops up on the screen if there is an error, since the default message is extremely long winded and I'd prefer to give a better explanation for the error that the user could understand.
private void Load_Click(object sender, RoutedEventArgs e)
{
if (comboBox.SelectedItem.ToString() == "Department Staff")
{
try
{
DataTable dt = dataSource.DataTableQuery("SELECT * FROM DepartmentStaff");
dataGrid.ItemsSource = dt.DefaultView;
}
catch (NullReferenceException ex)
{
MessageBox.Show("Unable To Connect To Database, Please Try Again Later.", ex.ToString());
}
}
else
{
try
{
DataTable dt = dataSource.DataTableQuery("SELECT * FROM Department");
dataGrid.ItemsSource = dt.DefaultView;
}
catch (NullReferenceException ex)
{
MessageBox.Show("Unable To Connect To Database, Please Try Again Later.", ex.ToString());
}
}
Take a look more carefully on the Message.Show() arguments:
Message.Show(text, caption); //the first one is text, the second one is caption.
The second argument is the caption (or title) while the first one is the message. Now in your use, you put up your exception message (which typically is very long) as the caption and that's why you get an "extremely long winded" caption (not message).
MessageBox.Show("Unable To Connect To Database, Please Try Again Later.", ex.ToString());
Don't do that! Instead, do it like this:
MessageBox.Show("Unable To Connect To Database, Please Try Again Later. " + ex.ToString(), "Error");
Simply put "Error" as caption argument.
I am using this syntax to write errors to a text file for logging in my Global.axax - it overwrites each time and only logs the most recent error. While this is helpful, it is not as helpful as I need it to be. How can I log each error that is raised?
This is my current code that only logs the most recent:
void Application_Error(object sender, EventArgs e)
{
Exception CurrentException = Server.GetLastError();
Server.ClearError();
if (CurrentException != null)
{
try
{
using (StreamWriter sw = new StreamWriter(Server.MapPath("HereAreErrors.txt")))
{
sw.WriteLine(CurrentException.ToString());
sw.Close();
}
}
catch (Exception ex) { }
}
}
As others have stated you're better off using an existing log tool to handle your logging. They have a myriad of features and, best of all, are maintained by someone else!
With that said, and in the interest of answering the question as asked, here's how to resolve your problem. It has the added benefit of creating the file if it doesn't exist.
void Application_Error(object sender, EventArgs e)
{
Exception CurrentException = Server.GetLastError();
Server.ClearError();
if (CurrentException != null)
{
try
{
File.AppendAllText(Server.MapPath("HereAreErrors.txt"), CurrentException.ToString());
}
catch (Exception ex) { }
}
}
I have a code segment that is responsible for orchestrating the execution of a few modules and it is very sensitive to errors - I want to make sure I log and alert about every exception that occurs.
Right now I have something like this:
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
}
catch (Exception ex)
{
string errorMessage = string.Format("Module A failed doing it's thing. Specific exception: {0}", ex.Message);
// Log exception, send alerts, etc.
}
try
{
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
string errorMessage = string.Format("Module B failed doing it's thing. Specific exception: {0}", ex.Message);
// Log exception, send alerts, etc.
}
// etc for other modules.
It looks to me that the multiple try-catch is making this segment less readable. Is it indeed the right thing to do?
Yes, it's the right thing.
But you should have the performance in in mind, maybe it's better to put all method calls in one try/catch and add stack trace and error information in the exception in the methiod itself.
public void ModuleA.DoSomethingA()
{
throw new Exception("Error in module A");
}
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
// get information about exception in the error message
}
You did well.
This way, you can process the error after each module. If you want to run it all and then do error handling, consider this alternative:
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch(ModuleAException ex)
{
// handle specific error
}
catch(ModuleBException ex)
{
// handle other specific error
}
catch (Exception ex)
{
// handle all other errors, do logging, etc.
}
i think that depends on the approach that you want to follow.
It seems like you error messsages are different for each module that raises exception so i guess the approach that you followed is right.
you could have put the whole thing in a big try - catch block then in that case you will not know which module caused the exception as a generic excpetion gets printed.
try
{
ModuleAResult aResult = ModuleA.DoSomethingA();
ModuleBResult bResult = ModuleB.DoSomethingB();
}
catch (Exception ex)
{
string errorMessage = string.Format("Either Module A or B failed", ex.Message);
// Log exception, send alerts, etc.
}
So if you want your exception handling to not be cleaner use the above code.
Otherwise what you followed is absolutely fine.
I have a line:
string[] cPathDirectories = Directory.GetDirectories(Properties.Settings.Default.customerFolderDirectory);
that will throw the error "Path is not of legal form" if the user didn't specify a search path (this setting is saved as String.Empty at this point). I would like throw this error to say, "Hey you idiot, go into the application settings and specify a valid path" instead. Is there a way to do this instead of:
...catch (SystemException ex)
{
if(ex.Message == "Path is not of legal form.")
{
MessageBox.Show("Hey you idiot, go into the application settings and specify a valid path","Error");
}
else
{
MessageBox.Show(ex.Message,"Error");
}
}
No, you need to check what the type of the exception is and catch that explicitly. Testing for strings in exception messages is a bad idea because they might change from one version of the framework to another. I'm pretty sure Microsoft doesn't guarantee that a message will never change.
In this case, looking at the docs you might be getting either a ArgumentNullException or ArgumentException, so you need to test for that in your try/catch block:
try {
DoSomething();
}
catch (ArgumentNullException) {
// Insult the user
}
catch (ArgumentException) {
// Insult the user more
}
catch (Exception) {
// Something else
}
Which exception you need here, I have no idea. You need to determine that and structure your SEH block accordingly. But always try to catch exceptions, not their properties.
Note the last catch is highly recommended; it ensures that if something else happens you won't get an unhandled exception.
you might check for an argument exception
...catch (SystemException ex)
{
if(ex is ArgumentException)
{
MessageBox.Show("Hey you idiot, go into the application settings and specify a valid path","Error");
}
else
{
MessageBox.Show(ex.Message,"Error");
}
}
That's an ArgumentException:
catch (ArgumentException) {
MessageBox.Show("Please enter a path in settings");
} catch (Exception ex) {
MessageBox.Show("An error occurred.\r\n" + ex.Message);
}
A couple ways to go about it.
First, just check the setting first before you make the GetDirectories() call:
if(string.IsNullOrEmpty(Properties.Settings.Default.customerFolderDirectory))
{
MessageBox.Show("Fix your settings!");
}
else
{
string[] cPathDirectories = Directory.GetDirectories(Properties.Settings.Default.customerFolderDirectory);
}
Or catch a more specific exception:
catch (ArgumentException ex)
{
MessageBox.Show("Hey you idiot, go into the application settings and specify a valid path","Error");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I'd probably go with the former, since then you don't run into a penalty (albeit minor) for exception throwing and can do any other validation you want such as checking whether the path exists, etc.
If you prefer the latter, though, you can find the list of exceptions Directory.GetDirectories() throws here, so you can tailor your messages appropriately.
P.S. I also wouldn't call your users idiots, but that's between you and your god. :)
Yes, you can again throw exception from catch block, example:
catch (SystemException ex)
{
if(ex.Message == "Path is not of legal form.")
{
throw new Exception("Hey you idiot, go into the application settings and specify a valid path", ex);
}
else
{
MessageBox.Show(ex.Message,"Error");
}
}