Whats the difference between Exception's .ToString() and .Message? - c#

I'm looking through some code and I found e.ToString() and I was wondering if there is a difference to using the ToString() method instead of .Message ?
Reading below, it sounds like it returns more info.
From Microsoft's Docs
ToString
Supported by the .NET Compact Framework.
Overridden. Creates and returns a string representation of the current exception.
Message
Supported by the .NET Compact Framework.
Gets a message that describes the current exception.

If you're looking to get as much information as possible in one go, call ToString():
The default implementation of ToString obtains the name of the class that threw the current exception, the message (my emphasis), the result of calling ToString on the inner exception, and the result of calling Environment.StackTrace. If any of these members is Nothing, its value is not included in the returned string.
It's convenient that you don't have to append all the individual elements together yourself, checking to make sure none are null, etc. It's all built in...
Exception.ToString Method
You can also check out the actual source code at reference.microsoft.com.

Try using .NET Reflector or similar to see what the ToString method on System.Exception is doing:
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public override string ToString()
{
return this.ToString(true);
}
private string ToString(bool needFileLineInfo)
{
string className;
string message = this.Message;
if ((message == null) || (message.Length <= 0))
{
className = this.GetClassName();
}
else
{
className = this.GetClassName() + ": " + message;
}
if (this._innerException != null)
{
className = className + " ---> " + this._innerException.ToString(needFileLineInfo) + Environment.NewLine + " " + Environment.GetRuntimeResourceString("Exception_EndOfInnerExceptionStack");
}
string stackTrace = this.GetStackTrace(needFileLineInfo);
if (stackTrace != null)
{
className = className + Environment.NewLine + stackTrace;
}
return className;
}

ToString() returns the Message along with the StackTrace.
ToString() will also recursively include InnerExceptions.
ToString() returns a much longer string which is much more useful than Message when tracking down errors.

You could always just try it and see:
try
{
throw new Exception("This is a test.");
}
catch ( Exception ex )
{
Console.WriteLine(ex);
Console.WriteLine(ex.Message);
}
(You will find that you are correct, .ToString is more informative, including among other things the stack trace.

The ToString methods returns the Message property along with information on where the error occured.
The Message property is intended for a short description of the error, and only contains what the person implementing the Exception put there. The resport from ToString contains additional information that is always included.
If you are running in debug mode, the error report contains more detailed information, e.g. line numbers in the call stack.

The e.ToString() will give you a detailed Message like PrintTrace i think which Display's the Exception Name and the Line where Exception was Thrown where e.Message Output's a Readable Message Only without Specification's.
You can check Exception base constructor

Related

What is the best practice for capturing all inner exception details? [duplicate]

This question already has answers here:
What is the proper way to display the full InnerException?
(11 answers)
Closed 9 years ago.
What is the best practice for logging complete exception details including all possible inner exceptions?
Currently, I use the following code:
try
{
//some code that throws an exception
}
catch(Exception ex)
{
do
{
Console.WriteLine(ex.Message+ex.StackTrace);
ex=ex.InnerException;
}while(ex!=null)
}
Are there any scenarios where this code may fail?
Have you tried just using ex.ToString()? It gives most (if not all) of the data you need to diagnose - including the message details, stack trace, and inner exceptions:
From MSDN:
ToString returns a representation of the current exception that is
intended to be understood by humans. Where the exception contains
culture-sensitive data, the string representation returned by ToString
is required to take into account the current system culture. Although
there are no exact requirements for the format of the returned string,
it should attempt to reflect the value of the object as perceived by
the user. The default implementation of ToString obtains the name of
the class that threw the current exception, the message, the result of
calling ToString on the inner exception, and the result of calling
Environment.StackTrace. If any of these members is null, its value is
not included in the returned string.
I have this extension method which suits my purposes just fine.
public static class ExceptionExtensions {
public static string ToMessageAndCompleteStacktrace(this Exception exception) {
Exception e = exception;
StringBuilder s = new StringBuilder();
while (e != null) {
s.AppendLine("Exception type: " + e.GetType().FullName);
s.AppendLine("Message : " + e.Message);
s.AppendLine("Stacktrace:");
s.AppendLine(e.StackTrace);
s.AppendLine();
e = e.InnerException;
}
return s.ToString();
}
}
And use it like this:
using SomeNameSpaceWhereYouStoreExtensionMethods;
try {
// Some code that throws an exception
}
catch(Exception ex) {
Console.WriteLine(ex.ToMessageAndCompleteStacktrace());
}
Update
Since I'm receiving upvotes for this answer I want to add that I stopped using this extension method, and now I'm just using exception.ToString(). It gives more information. So please, stop using this method, and just use .ToString(). See the answer above.

C# if exception is caught will it reach my return statement?

In System.IO there is a function:
string File.ReadAllText( string path );
I am trying to write a function that would call File.ReadAllText, take care of all possible exceptions and return true/false and store error message.
What I have is this:
public static class FileNoBS
{
public static bool ReadAllText( string path, out string text, out string errorMessage )
{
errorMessage = null;
text = null;
bool operationSuccessful = false;
try
{
text = System.IO.File.ReadAllText( path );
operationSuccessful = true;
}
catch ( ArgumentNullException e )
{
errorMessage = "Internal software error - argument null exception in FileNoBs.ReadAllText\nMessage: " + e.Message;
}
catch ( ArgumentException e )
{
errorMessage = "Internal software error - path is a zero-length string, contains only white space, or contains one or more invalid characters as defined by InvalidPathChars in FileNoBs.ReadAllText.\nMessage: " + e.Message;
}
catch ( PathTooLongException e )
{
errorMessage = "The specified path was too long.\nMessage: " + e.Message;
}
catch ( DirectoryNotFoundException e )
{
errorMessage = "The specified directory was not found.\nMessage: " + e.Message;
}
catch ( FileNotFoundException e )
{
errorMessage = "The file specified in path was not found.\nMessage: " + e.Message;
}
catch ( IOException e )
{
errorMessage = "An I/O error occurred while opening the file.\nMessage: " + e.Message;
}
catch ( UnauthorizedAccessException e )
{
errorMessage = #"UnauthorizedAccessException
path specified a file that is read-only.
-or-
This operation is not supported on the current platform.
-or-
path specified a directory.
-or-
The caller does not have the required permission.\nMessage: " + e.Message;
}
catch ( NotSupportedException e )
{
errorMessage = "path is in an invalid format.\nMessage: " + e.Message;
}
catch ( SecurityException e )
{
errorMessage = "You do not have the required permission.\nMessage: " + e.Message;
}
return operationSuccessful;
}
}
I don't understand how how control flow goes with functions that return value.
Let's say UnauthorizedAccessException gets caught, errorMessage is set to
errorMessage = "You do not have the required permission..."
I know that finally gets executed every time, but compiler won't let me do return inside finally block. So will my return get reached or not?
Another question is how to simplify this while still following official guidelines:
"In general, you should only catch those exceptions that you know how to recover from. "
I dread going through all functions that I will need from File class (Move, Copy, Delete, ReadAllText, WriteAllText) and then Directory class and doing all these long blocks of code just to catch all exceptions I don't care about and not catch too many of them cause Microsoft says it's bad.
Thank you.
EDIT: I got comments like this is not handling exceptions this is "something else".
I am client for my code and I want to do something like this:
if ( !FileNoBS.ReadAllText( path, text, errorMessage ) ) {
MessageBox.Show( errorMessage );
return;
}
// continue working with all errors taken care of - don't care for whatever reason file wasn't opened and read, user is notified and I am moving on with my life
Your return will be reached as there isn't a return in the try block or the catch block.
Generally, you only want to catch exceptions that you expect may occur and have a way of handling them. For example, you may want to handle the file not being found from the given path and return a default file instead. You should allow other exceptions not to be caught so you know that something unexpected has happened and not hide it by catching all exceptions.
As I said in my comment, you are better off handling the exceptions at a higher level and simply displaying the exception message rather than manually setting each message. I think in this case the message from the exception will be descriptive enough.
public static class FileNoBS
{
public static string ReadAllText(string path)
{
return System.IO.File.ReadAllText( path );
}
}
then use it like this at some higher level in your application. I typically have a general handler to handle all application exceptions and log them and display a message box if necessary.
try
{
var text = FileNoBS.ReadAllText("file.ext");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Instead of catching the exceptions you should try to avoid the situation that will lead to those exceptions being thrown in the first place. In your case you should have some input validation before calling ReadAllText
never accept a path that is null - you know this will lead to an exception so handle it before it does
never accept a path that leads to a file that does not exist - use File.Exists(path) prior to the call
never accept a malformed path E.g. the empty string or one with invalid characters - this will lead to an exception
These tests should be performed where the input originates. That is if the user types them in, validate them before using them. If they come from a DB or somewhere else validate there before use. If it's not user input they are all indications of a system error and should be treated as such, not as something the user should worry about.
Security exceptions can be somewhat harder to test up front and in many cases it is exceptional to get a violation and therefor perfectly ok to get an exception. It shouldn't crash the program of course but be handled with an errormessage to the user (if it's based on user input, if it's system generated data that leads to this, it's an idication of a system error that should be fixed at code level). It's often more appropriate to do this where the call happens than in some library method.
for IOExceptions they can be put into two buckets. Recoverable once (usually a retry) and unrecoverable once. As a minimum give the user feedback on the exception, so the user might have the option of retrying.
A very general rule that should be part of the error correction logic is to never have invalid data floating around the system. Make sure that all objects manage the invariants (Tools are available for this such as code contracts). Reject invalid input from the user (or other systems) when they are received instead of when they result in an exception.
If you do all the input validation and still have E.g. ArgumentNullException then that points to an error in the logic of the program, something that you want to be able to easily find in a test and correct before you release the bug. You shouldn't try and mask this error.
Provided no other error occurs, yes.
I'd add at the end:
catch (Exception e)
{
errormessage = "An unexpected error has occured.";
}
return operationSuccessful;
Though, this will always return the successful even if you got an error. I'm not sure if that's what you want, or if your variables are badly named.
The return statement is going to be called in case of any exception in your code, before it is placed at the end of the program before it exits.
I will suggest placing a single exception handler with a high level Exception type, like the 'Exception' type itself, and print or log the exception message. Specifying so many exception handlers in each method is going to take a lot of energy which your should actually put in the method itself.
try
{
return ReadAllText("path", "text", "error");
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
return false;
So if the method gets called, it will return immediately, otherwise the exception gets printed/logged and the method will return false.
You can however, mention a couple or few explicit exception handlers in some cases, where you think it will be beneficial.
Yes It will return the value.
But, better you handle return value in finally statement.
If in any case you want to return operationSuccessful value, then write finally block after catch blocks as follows,
finally
{
return operationSuccessful;
}

Get name of last called method

I have the following code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
try
{
this.CheckValue(true); // call method
}
catch(Exception ex)
{
// how to get here name of last called method
}
}
public int CheckValue(bool sender)
{
var qwe = int.Parse("qwe"); // invoke an exception
return 0;
}
}
I need to get in "catch block" name of last called method (in this case "CheckValue"), but it return that called method is "StringToNumber".
I try to get it using StackTrace:
stackTrace.GetFrame(1).GetMethod().Name; -> "Main"
MethodBase.GetCurrentMethod(); -> "Void .ctor()"
ex.TargetSite.Name; -> "StringToNumber"
It's possible to do this?
Short Answer:
Yes, You can!!!
I'd just play around with Extension Methods and the trick here, is to get the last frame of the desired class, otherwise it would get methods of mscorlib assembly. So here it go:
public static string GetLastCalledMethod<T>(this Exception ex)
{
var stackTrace = new System.Diagnostics.StackTrace(ex);
var lastFrame = stackTrace.GetFrames().FirstOrDefault(frame => frame.GetMethod().DeclaringType.FullName == typeof(T).FullName);
string methodName = string.Empty;
if (lastFrame != null)
methodName = lastFrame.GetMethod().Name;
return methodName;
}
Short Answer:
You can't.
Long Answer:
If you really need to do that, you will need to perform logging code in all the methods you want to track.
You can create a global variable (ugh) to store a MethodInfo with the last called method, and inside every method, set it to MethodBase.GetCurrentMethod(). Then whenever you want, you can examine that variable to see which method set it last.
In your case, you probably are trying to determine which method the exception was thrown in. You are looking at TargetSite, which returns the lowest method in the hierarchy, whereas you seem to want the one immediately below the current method. If simply examining Exception.StackTrace doesn't provide enough information, you might be able to parse out information from StackTrace and use reflection to get a MethodInfo. Usually, the StackTrace is good enough.
You may also be able to throw a new exception in the top-level method, so you can get the TargetSite from the new one.
Summary:
If Exception.StackTrace doesn't provide enough information, then you will either have to:
Perform logging code in each method you want to check for.
Parse out what information you can get from the Exception.
Change the exception throwing scheme to throw a new exception with InnerException set to the original exception.
I don't know why you want to do this.. because this is expected behaviour. The site of the exception is what you're being shown.. within the int.Parse() calls.
That being said.. if you really want to do this, you need to wrap a try.. catch in CheckValue, and re-throw the exception from there, but in a way that breaks the call stack.. like so:
public int CheckValue(bool sender) {
try {
var qwe = int.Parse("qwe"); // invoke an exception
return 0;
}
catch (Exception ex) {
throw ex; // this breaks the call stack and re-throws the exception from here..
}
}
Then, ex.TargetSite.Name == "CheckValue". I'm still not sure why you'd want to do this.. as a stack trace will actually show you where it all unwinds from after failure.

Exception with null message

I found that exception message can't be null in C#, and after trying this
var ex = new Exception(null);
Console.WriteLine(ex.Message);
I get the following message:
Exception of type 'System.Exception' was thrown.
But, in this case,
var ex = new Exception(string.Empty);
Console.WriteLine(ex.Message);
the message is just empty.
How this can be explained? Do you think this is expected behavior?
The other answers (not including the answer from chopikadze) seem to be based on a misreading of the facts. Neither example is throwing an exception.
Rather, in the first example, the constructed exception ex is providing a message because the value of the constructor's message parameter was null. The message is "an exception of type 'System.Exception' was thrown".
It's a fairly common practice to have some fallback behavior when an object reference is null, so that's "how it can be explained". Whether it is "expected", of course, depends on your expectations.
Throwing exceptions in the course of handling exceptions can be problematic, so the framework designers must have chosen this behavior to reduce this possibility. It would have been a nightmare, frankly, if we all had to cover the possibility that exception messages might be null.
EDIT
The behavior is also documented in the remarks for the Message property: "If no message was supplied to the constructor for the current instance, the system supplies a default message that is formatted using the current system culture."
I looked in the CLI spec and in the C# spec, and I found no mention of a requirement that Message have a non-null return value, so I guess that supports the view that this behavior is a framework design decision.
Actually constructor doesn't need string, you can absolutely surely use null. This is reflectored part of Exception class:
internal string _message;
public Exception(string message)
{
this.Init();
this._message = message;
}
private void Init()
{
this._message = null;
this._stackTrace = null;
this._dynamicMethods = null;
this.HResult = -2146233088;
this._xcode = -532462766;
this._xptrs = IntPtr.Zero;
this._watsonBuckets = null;
this._ipForWatsonBuckets = UIntPtr.Zero;
this._safeSerializationManager = new SafeSerializationManager();
}
public virtual string Message
{
[SecuritySafeCritical]
get
{
if (this._message != null)
{
return this._message;
}
if (this._className == null)
{
this._className = this.GetClassName();
}
return Environment.GetRuntimeResourceString("Exception_WasThrown", new object[] { this._className });
}
}
So if you use null as message in constructor, localized string like "Exception of type 'System.Exception' was thrown." will be used as Message. It means - there is still your Exception, not another one, but it's property Message returns another (calculated) value instead of null from constructor.
I think that it's defined by design (and maybe is used in another places) that Exception.Message should be always not null. So if we want to allow developers use default constructor for Exception class (for example, for using with reflection or for allowing to populate properties later) but we also want to has Message always not null - we should wrap Message with something. I think, one of the possible place of Message usage is default dialog box showed after exception occurs. This way there could be used just Message property, instead of checking - is Message property equals to null etc.
string.Empty is not null it is a constant for "".
Your first example is giving a default message, your second example is an empty string
Yes, the constructor you are using requires a string. String.Empty is not the same as null therefore it will throw an exception.
http://msdn.microsoft.com/en-us/library/system.exception.aspx

.NET error handling

I have been writing .NET applications and have been impressed with the error handling included in the framework.
When catching an error that has been throw by the processes or somewhere in the code I like to include the message (ex.Message, which is usually pretty general) but also the stacktrace (ex.stacktrace) which helps to trace the problem back to a specific spot.
For a simple example let's say for instance that we are recording numbers to a log in a method:
public void ExampleMethod(int number){
try{
int num = number
...open connection to file
...write number to file
}
catch(Exception ex){
.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally{
...close file connection
}
}
Is there any way to see the method called (in this case ExampleMethod) with the specific number that was passed that potentially crashed the method call? I believe you could log this perhaps in the catch block but I am interested essentially in catching the method call and parameters that caused the system to throw the exception.
Any ideas?
I suggest stuffing the parameter values into the exception's Data dictionary, e.g.
public void ExampleMethod(int number) {
try {
int num = number
...open connection to file
...write number to file
}
catch(Exception ex) {
ex.Data["number"] = number;
//.... deal with exception (ex.message,ex.stacktrace etc...)
}
finally {
//...close file connection
}
Another advantage of this method is that you can stuff the parameters in the catch block, then re-throw the exception and log it somewhere else without losing the stack trace, e.g.
catch(Exception ex) {
ex.Data["number"] = number;
throw;
}
If you want to know the value of the parameters in your method, then there is only one way, IMO, to do it - you need to repackage the exception with data.
For example:
int param1 = 10;
string param2 = "Hello World";
try
{
SomeMethod(param1, param2)
}
catch(SomeExpectedException e)
{
throw new MyParameterSensitiveException(e, param1, param2);
}
You basically repackage the original exception as the inner exception of another exception, and additionally supply the parameters you used to call the method. Then you could inspect that in some way to figure out what went wrong.
The accepted answer and many of the solutions described will work fine but what you're doing is littering your source with a slightly different blob of code depending on what parameters are in your method signature.
When it comes time to add a new parameter you need to remember to update your handler to add that new parameter. Or if you remove a parameter then you need to remember to remove the parameter from your exception handler.
What if you have a two or more try..catch blocks? Then you now have two blocks of code to keep up to date. Definitely not refactor friendly.
Another approach is to remove the logging code use a technique called Aspect Oriented Programming.
One such tool to facilitate this is a product called PostSharp.
With PostSharp you can write a logger than is invoked whenever an exception is thrown without the need for messy method and parameter specific code. For example (using version 1.5 of PostSharp):
LoggerAttribute.cs -
[Serializable]
public class LoggerAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
Console.WriteLine(eventArgs.Method.DeclaringType.Name);
Console.WriteLine(eventArgs.Method.Name);
Console.WriteLine(eventArgs.Exception.StackTrace);
ParameterInfo[] parameterInfos = eventArgs.Method.GetParameters();
object[] paramValues = eventArgs.GetReadOnlyArgumentArray();
for (int i = 0; i < parameterInfos.Length; i++)
{
Console.WriteLine(parameterInfos[i].Name + "=" + paramValues[i]);
}
eventArgs.FlowBehavior = FlowBehavior.Default;
}
}
You then decorate your classes with the LoggerAttribute:
[Logger]
public class MyClass
{
public void MyMethod(int x, string name)
{
// Something that throws an exception
}
}
Anything that throws an exception in MyMethod will cause the OnException method to be executed.
There are two versions of PostSharp. Version 1.5 is free and open sourced under the GPL and is targeted at .NET 2.0. PostSharp 2.0 is not entirely free but its community edition will support the basic functionality described above.
In order to do this:
public void MyProblematicMethod(int id, string name)
{
try
{
object o = null;
int hash = o.GetHashCode(); // throws NullReferenceException
}
catch (Exception ex)
{
string errorMessage = SummarizeMethodCall(MethodBase.GetCurrentMethod(), id, name);
// TODO: do something with errorMessage
}
}
...and get this:
"MyProblematicMethod invoked: id = 1, name = Charlie"
...you could do something like this:
public static string SummarizeMethodCall(MethodBase method, params object[] values)
{
var output = new StringBuilder(method.Name + " invoked: ");
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
output.AppendFormat("{0} = {1}",
parameters[i].Name,
i >= values.Length ? "<empty>" : values[i]
);
if (i < parameters.Length - 1)
output.Append(", ");
}
return output.ToString();
}
You could make a class that inherits Exception and add some arguments to it so you could pass the number to it.
You can get the method name and the parameters like this,
try
{
int a = 0;
int i = 1 / a;
}
catch (Exception exception)
{
StackTrace s = new StackTrace(exception);
StackFrame stackFrame = s.GetFrame(s.FrameCount - 1);
if (stackFrame != null)
{
StringBuilder stackBuilder = new StringBuilder();
MethodBase method = stackFrame.GetMethod();
stackBuilder.AppendFormat("Method Name = {0}{1}Parameters:{1}", method.Name, Environment.NewLine);
foreach (ParameterInfo parameter in method.GetParameters())
{
stackBuilder.AppendFormat("{0} {1}", parameter.ParameterType.FullName, parameter.Name);
stackBuilder.AppendLine();
}
// or use this to get the value
//stackBuilder.AppendLine("param1 = " + param1);
//stackBuilder.AppendLine("param2 = " + param2);
}
}
I am not sure whether you can get the parameter values directly off the stack like a debugger.
The Automatic Exception Handling from Crypto Obfuscator can do what you need.
The exception reports include all pertinent information including full stack trace info along with the values of all method arguments and local variables, plus the system information, the time of the exception, the build number, and optional developer defined custom data like log files, screenshots, etc.
DISCLAIMER: I work for LogicNP Software, the developer of Crypto Obfuscator.

Categories