Hello I would like to write my userdefined exception to a log file.
So Instead of throwing my exception I would like to log that message into a txt file.
The constructor for my exception looks like this:
public OpenFileException(string pathToOpen, Exception innerexception)
: base("Couldn't find the path: " + pathToOpen, innerexception)
{
this.pathToOpen = pathToOpen;
}
This is how I am logging my exception at the moment:
try
{
string data = Read(txtLocation.Text);
txtInfo.Text = data;
}
catch (Exception ex)
{
WriteLog("[" + DateTime.Now + "]" + " " + ex.Message);
MessageBox.Show(" ");
throw new OpenFileException(txtLocation.Text, ex);
}
So what I'm asking is. How can I log my string "Couldn't find the path: " to a txt file?
I would normally catch and log the user defined exception outside the normal try/catch
try {
try {
string data = Read(txtLocation.Text);
txtInfo.Text = data;
} catch (Exception ex) {
throw new OpenFileException(txtLocation.Text, ex);
}
....
} catch(OpenFileException ex) {
WriteLog("[" + DateTime.Now + "]" + " " + ex.Message);
MessageBox.Show(" ");
} catch(Exception ex) {
WriteLog("[" + DateTime.Now + "]" + " " + ex.Message);
MessageBox.Show(" ");
}
You are creating a user defined exception so you can handle it differently
It looks a bit overkilling, why don't you use Log4Net and let it write files or send you emails depending on its configuration in the app.config?
basically you get all what you can want out of the box with no effort, then you can concentrate on what matters the most.
even if you decide to keep your current logic, I would anyway create a Logger class which does everything instead of having to specify DateTime.Now and other magic in every single catch block of your application.
You can use, instead of reinvent the wheel, log4net http://logging.apache.org/log4net/ or NLog http://nlog-project.org/wiki/Documentation both worth the effort to learn and use even in simple applications.
You need to find a way to get your exception thrown when a file is not found.
I don't think this is a good idea, because .NET already throws the FileNotFoundException when a file is not found. You should catch that and log the message that way.
try
{
string data = Read(txtLocation.Text);
txtInfo.Text = data;
}
catch (FileNotFoundException ex)
{
string log = String.Format("[{0}] Couldn't find the path: {1}"
, DateTime.Now
, ex.FileName);
WriteLog(log);
}
Don't make a new exception type when one already exists.
(Forgive the idiosyncrasies in my formatting)
From Framework Desing Guidelines:
Do override ToString when your exception provides extra properties.
Then you can just call log.Error(exception) and it will be logged just the way you wrote ToString() without extra actions.
Related
I am new to C# and I'm struggling with very basic stuff... for instance I am now trying to compare an exception that I KNOW will print exactly the phrase "ORA-28007: the password cannot be reused" if I use Response.Write(ex.Message). However, in the block below, the comparison between ex.Message and the string just provided fails and it returns that Unhandled Exception I've put in the else clause... How should I be comparing the exception with the string?
catch (Exception ex)
{
if (ex.Message == "ORA-28007: the password cannot be reused")
{
Response.Write(ex.Message);
// TODO : Correct the exception to be presented in the popup instead of the same page.
// display = "The password cannot be reused! Pick a new one.";
// ClientScript.RegisterStartupScript(this.GetType(),
// "Error.", "alert('" + display + "');", true);
}
else
{
Response.Write("Unhandled exception: " + ex.Message);
}
}
If you're using the Oracle Data Provider for .NET you can catch OracleExceptions instead of Exceptions and get some more details by looking at the Errors property, which gives a list of OracleError objects:
catch(OracleException oex)
{
foreach (OracleError error in oex.Errors)
{
Console.WriteLine("Error Message: " + error.Message);
Console.WriteLine("Error Source: " + error.Source);
if(error.Number == 28007)
{
// do specific stuff
}
}
}
I am using Elmah for error reporting in my applications.
Usually if there's an error I catch it, craft a custom message and throw it back again.
catch (Exception ex)
{
var e = new Exception("Failed to get Intake Statuses <br />"
+ " (#PageNumber = " + pageNumber + ", #PageSize = " + pageSize + ".<br />"
+ " Error: " + ex);
ErrorLogger.LogErrorManually(e);
throw new Exception(e.Message);
}
Now the issue arises if there is an error in the custom error that I am created.
What are the best practices to handle that? Do I create another sub Try/Catch?
You can do the following:
Create a method say A with try catch and lets call your function whose catch you have given in description as B.
In your B catch just use throw so that your stack trace will not go away.
On exception in B catch it will navigate to catch A and thus you can show the message as you like it.
I need to get only the exception message without the call stack or any other string.
I thought that using Exception.Message would be enough, but it keeps giving me the message mixed with the call stack. Do you know how to get rid of all the rest of information that comes with Exception.Message?
try
{
}
catch (Exception ex)
{
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Message", "alert('" + ex.Message + "');", true);
}
This is what I get when I use ex.Message:
System.Web.Services.Protocols.SoapException: The server can not process the request. ---> System.NullReferenceException: Object reference not set to an instance of an object in . in WebService.ProcessRequestArc.............--- End of inner exception stack trace ---
When what I only need is:
The server can not process the request
Is there any way to get only that part of the message?
You are not using the Message property here...
ex.ToString()
You need
ex.Message
Also, is this Alert only for your convenience? You should consider maybe having an error label on your screen, since the pop-up can always look messy.
EDIT: You should also look to catch more specific exceptions, instead of the catch all type of handling you have. Take a look at the possible exceptions in your try block, and accommodate them...for example...
catch (SoapException ex)
{
//handle
}
catch (Exception e)
{
//handle
}
Make sure the more specific exceptions come before the final Exception block.
Exception.Message is correct for generic Exceptions.
Check out the more detailed info available for SoapException
Here is an example:
namespace ExceptionHandlingTestConsole
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("do something");
throw new System.Web.Services.Protocols.SoapException();
//throw new Exception("my exception", new Exception("my inner exception"));
}
catch (System.Web.Services.Protocols.SoapException soapEx)
{
Console.Write("Detail: ");
Console.WriteLine(soapEx.Detail);
Console.Write("Node: ");
Console.WriteLine(soapEx.Node);
Console.Write("Role: ");
Console.WriteLine(soapEx.Role);
Console.Write("Message: ");
Console.WriteLine(soapEx.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine("inner exception msg: " + ex.InnerException.Message);
}
}
Console.ReadKey();
}
}
}
Using ex.Message will only return the developer's custom message or, if none was specified, then the name of the exception class (i.e. "Exception of type 'SomeException' was thrown").
public virtual String Message
{
get
{
if (_message != null)
return _message;
if (_className == null)
_className = GetClassName();
return Environment.GetResourceString("Exception_WasThrown", _className);
}
}
If some piece of code further down the chain stored the entire stack trace in the exception's Message property before throwing it, that might explain what you're seeing.
What you're describing is unexpected behavior, and is more typical of calling ex.ToString(), which concatenates the Message (or class name if none), the result of ToString() on the inner exception, and the stack trace.
public override String ToString()
{
String message = Message;
String s;
if (message == null || message.Length <= 0)
s = GetClassName();
else
s = GetClassName() + ": " + message;
if (_innerException != null)
s = s + " ---> " + _innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine +
" " + Environment.GetResourceString("Exception_EndOfInnerExceptionStack");
string stackTrace = GetStackTrace(needFileLineInfo);
if (stackTrace != null)
s += Environment.NewLine + stackTrace;
return s;
}
You are really close... What you have is this:
try
{
}
catch (Exception ex)
{
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Message", "alert('" + ex.ToString() + "');", true);
}
What you need is this:
try
{
}
catch (Exception ex)
{
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Message", "alert('" + ex.Message + "');", true);
}
From the documentation:
Error messages target the developer who is handling the exception. The text of the Message property should completely describe the error and, when possible, should also explain how to correct the error. Top-level exception handlers may display the message to end-users, so you should ensure that it is grammatically correct and that each sentence of the message ends with a period. Do not use question marks or exclamation points. If your application uses localized exception messages, you should ensure that they are accurately translated.
It is also more helpful to use a Web Service reference over an WCF Service reference. See the answer on this post for more information. Or, you could simply just throw a Soap Exception yourself.
Seriously, how can you handle all those exceptions without going nuts? Have I read one too many articles on exception handling or what? I tried refactoring this a couple of times and each time I seem to end up with something even worse. Maybe I should admit exceptions do happen and simply enjoy coding just the happy path? ;) So what's wrong with this code (besides the fact that I was lazy enough just to throw Exception instead of something more specific)? And by all means, don't go easy on me.
public void Export(Database dstDb)
{
try
{
using (DbConnection connection = dstDb.CreateConnection())
{
connection.Open();
DbTransaction transaction = connection.BeginTransaction();
try
{
// Export all data here (insert into dstDb)
transaction.Commit();
}
catch (SqlException sqlex)
{
ExceptionHelper.LogException(sqlex);
try
{
transaction.Rollback();
}
catch (Exception rollbackEx)
{
logger.Error("An exception of type " + rollbackEx.GetType() +
" was encountered while attempting to roll back the transaction.");
}
throw new Exception("Error exporting message " + Type + " #" + Id + ": [" + sqlex.GetType() + "] " + sqlex.Message, sqlex);
}
catch (Exception ex)
{
try
{
transaction.Rollback();
}
catch (Exception rollbackEx)
{
logger.Error("An exception of type " + rollbackEx.GetType() +
" was encountered while attempting to roll back the transaction.");
}
throw new Exception("Error exporting message " + Type + " #" + Id + ": [" + ex.GetType() + "] " + ex.Message, ex);
}
}
try
{
Status = MessageStatus.FINISHED;
srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
}
catch (Exception statusEx)
{
logger.ErrorException("Failed to change message status to FINISHED: " +
Type + " #" + Id + ": " + statusEx.Message, statusEx);
}
}
catch (Exception importEx)
{
try
{
Status = MessageStatus.ERROR;
srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
}
catch (Exception statusEx)
{
logger.ErrorException("Failed to change message status to ERROR: " +
Type + " #" + Id + ": " + statusEx.Message, statusEx);
}
AddErrorDescription(importEx.Message);
throw new Exception("Couldn't export message " + Type + " #" + Id + ", exception: " + importEx.Message, importEx);
}
}
Btw. So many times I tried really hard to be as specific as possible when forming questions - the result was no visits, no answers and no idea how to solve the problem. This time I thought about all the times when someone else's question caught my attention, guess this was the right thing to do :)
Update:
I've tried putting some of the tips into practice and here's what I came up with so far. I decided to change the behavior slightly: when it's not possible to set message status to FINISHED after successful export I consider it as job not fully done and I rollback and throw an exception. If you guys still have some patience left, please let me know if it's any better. Or throw some more criticism at me. Btw. Thanks for all the answers, I analyze every single one of them.
Throwing an instance of System.Exception didn't feel right, so I got rid of that, as suggested, and instead decided to introduce a custom exception. This, by the way, also doesn't seem right - overkill? This appears to be fine with public methods but a bit over-engineered for a private member, yet still I want to know there was a problem with changing message status instead of a problem with database connection or something.
I can see couple of ways of extracting methods here, but all of them seem to mix responsibilities which jgauffin mentioned in his comment: managing database connection, handling database operations, business logic (export data). Say the ChangeStatus method - it's some level of abstraction - you change the status of a message and you're not interested in how this thing happens, how the message is persisted, etc. Maybe I should use a Data Mapper pattern to further separate responsibilities, but in this still quite simple scenario I thought I'd get away with Active Record. Maybe the whole design is so convoluted right now, that I don't see where to make the cuts?
public void Export(Database dstDb)
{
try
{
using (DbConnection connection = dstDb.CreateConnection())
{
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction())
{
// Export all data here (insert into dstDb)
ChangeStatus(MessageStatus.FINISHED);
transaction.Commit();
}
}
}
catch (Exception exportEx)
{
try
{
ChangeStatus(MessageStatus.ERROR);
AddErrorDescription(exportEx.Message);
}
catch (Exception statusEx)
{
throw new MessageException("Couldn't export message and set its status to ERROR: " +
exportExt.Message + "; " + statusEx.Message, Type, Id, statusEx);
}
throw new MessageException("Couldn't export message, exception: " + exportEx.Message, Type, Id, exportEx);
}
}
private void ChangeStatus(MessageStatus status)
{
try
{
Status = status;
srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
}
catch (Exception statusEx)
{
throw new MessageException("Failed to change message status to " + status + ":" + statusEx.Message, statusEx);
}
}
Datasets are the root of all evil ;) Try using a ORM instead.
Read about single responsibility principle. your code does a lot of different things.
Do not catch exceptions only to rethrow them
Use using statement on transaction and connection.
No need to catch all different exceptions when all exception handlers do the same thing. The exception details (Exception type and Message property) will provide info.
Additionally to the great answer of jgauffin.
6 . don't catch exceptions just to log them. catch them on the top most level and log all the exceptions there.
Edit:
Because exception logging all over the place has at least these disadvantages:
The same exception may be logged several times, which fills the log unnecessarily. It's hard to tell how many errors actually occurred.
If the exception is caught and handled or ignored by the caller, there are still error messages in the log file, which is at least confusing.
Exception handling is a well discussed and is implemented in a well varied number of ways. There are some rules I try to abide by when handling exceptions:
Never throw System.Exception, generally there are enough types of exceptions to fill your requirement, if not, specialise. See: http://www.fidelitydesign.net/?p=45
Only ever throw an exception if the method itself cannot do anything but throw an exception. If a method can recover/handle expected variations of input/behaviour, then don't throw an exception. Throwing exceptions is a resource-intensive process.
Never catch an exception just to rethrow it. Catch and re-throw if you need to perform some additional work, such as reporting the exception, or wrapping the exception in another exception (typically I do this for WCF work, or transactional work).
These are just the things I do personally, a lot of developers prefer doing it ways in which they are comfortable....
Create a log class that handles fall backs for its own failures (i.e. tries SQL, if that fails writes to event log, if that fails, writes to a local log file, etc).
Also I don't recommend you catch an error and throw a different one. Every time you do so you are losing valuable trace/debug information about the original exception source.
public void Export(Database dstDb)
{
try
{
using (DbConnection connection = dstDb.CreateConnection())
{
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction())
{
// Export all data here (insert into dstDb)
ChangeStatus(MessageStatus.FINISHED);
transaction.Commit();
}
}
}
catch (Exception exportEx)
{
LogError(exportEx);// create a log class for cross-cutting concerns
ChangeStatus(MessageStatus.ERROR);
AddErrorDescription(exportEx.Message);
throw; // throw preserves original call stack for debugging/logging
}
}
private void ChangeStatus(MessageStatus status)
{
try
{
Status = status;
srcDb.UpdateDataSet(drHeader.Table.DataSet, HEADERS,
CreateHeaderInsertCommand(), CreateHeaderUpdateCommand(), null);
}
catch (Exception statusEx)
{
Log.Error(statusEx);
throw;
}
}
Also for any situation where you feel there are additional try/catch blocks needed, make them their own method if they are too ugly. I like Stefan Steinegger's answer, where the top level call in your app is the best place to catch.
Part of the problem here I imagine is that something is mutable that causes you to try to set the status after a failure. If you can factor your object to being in a consistent state whether or not your transaction works you don't have to worry about that part.
I am serializing a XML File.During the serialization ,I am receiving general exception.It is hard trace the problem.
my code is:
try
{
string m_fileName = #"d:\Xml\Person.xml";
XmlSerializer xmlPerSerlzr = new XmlSerializer(typeof(person));
txtWrt = new StreamWriter(m_fileName);
xmlPerSerlzr.Serialize(txtWrt, person);
}
catch(Exception serExp)
{
MessageBox.Show("Exception is :" + serExp.Message.ToString());
}
Error Message :
There was an error reflecting type "Person"
My question is how can i force the CLR to emit the exact error ?
Check the type of the exception, e.g.
serExp.GetType().ToString()
and check for an inner exception (both type and message).
That should give you some more useful info.
Use:
exc.ToString();
In Debug mode in Exception DialogBox, select View details option.
Probably You don't implement 0-parameter constructor.
I think it is better to check also the stack trace and the inner exception.
You can use something like that
string GetExceptionString(Exception ex)
{
string str = "";
while (ex != null)
{
str += ex.Message + "\n" + ex.StackTrace;
ex = ex.InnerException;
}
return str;
}
Use
serExp.StackTrace
instead of
serExp.Message.ToString()
Set a breakpoint in the catch clause, then run in debug mode. You can then explore the exception object easier and figure out what is going on.