I've created a custom exception for a very specific problem that can go wrong. I receive data from another system, and I raise the exception if it bombs while trying to parse that data. In my custom exception, I added a field called "ResponseData", so I can track exactly what my code couldn't handle.
In custom exceptions such as this one, should that extra response data go into the exception "message"? If it goes there, the message could be huge. I kind of want it there because I'm using Elmah, and that's how I can get at that data.
So the question is either:
- How can I get Elmah to record extra information from a field in a custom exception
OR
- Should extra exception details go into the "message" property?
In custom exceptions such as this one,
should that extra response data go
into the exception "message"?
No, as Sören already pointed out. However, your exception type could override ToString and sensibly add the response data information there. This is a perfectly normal practice followed by many of the exception types in the BCL (Base Class Library) so you will not find yourself swimming against the tide. For example, have a look at the System.IO.FileNotFoundException.ToString implementation in SSCLI (Rotor):
public override String ToString()
{
String s = GetType().FullName + ": " + Message;
if (_fileName != null && _fileName.Length != 0)
s += Environment.NewLine + String.Format(Environment.GetResourceString("IO.FileName_Name"), _fileName);
if (InnerException != null)
s = s + " ---> " + InnerException.ToString();
if (StackTrace != null)
s += Environment.NewLine + StackTrace;
try
{
if(FusionLog!=null)
{
if (s==null)
s=" ";
s+=Environment.NewLine;
s+=Environment.NewLine;
s+="Fusion log follows: ";
s+=Environment.NewLine;
s+=FusionLog;
}
}
catch(SecurityException)
{
}
return s;
}
As you can see, it appends the content of FusionLog property, which represent extra information in case of assembly load failures.
How can I get Elmah to record extra
information from a field in a custom
exception
ELMAH stores the result of calling ToString on an exception as the details of the error so if you have ToString implemented as prescribed, the information would get logged without further work. The only issue is that the logged detail will be unstructured text.
You shouldn't fill .Message with debug information, but rather with a concise, helpful piece of text.
http://msdn.microsoft.com/en-us/library/system.exception.message.aspx
The text of Message should completely describe the error and should, when possible, explain how to correct it. The value of the Message property is included in the information returned by ToString.
The Message property is set only when creating an Exception. 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.
[..]
Notes to Inheritors:
The Message property is overridden in classes that require control over message content or format. Application code typically accesses this property when it needs to display information about an exception that has been caught.
The error message should be localized.
Response data does not qualify as a description.
Not being familiar with elmah, I can't tell you how to extend the Exception class while using it. Does elmah implement its own subclass to Exception? Or an interface? Can you subclass it yourself?
The Exception class contains a dictionary (named Data, I believe) that you can use to associate custom data with a vanilla exception.
I don't fully understand the question but you seem to be asking what to do with additional exception data, if that is not your question feel free to ignore this.
I think an important question to ask is what exactly is the exception message for? It is not for knowing where the exception came from, the stack trace is for that; it is not to encapsulate an exception in a more general one, that should be done with the InnerException field; in the case where your exception is only raised from a particular place in your code it isn't even for describing what kind of error you had - thats what the type of the exception is for.
Generally I use the message field to provide simple, human-readable tips that a programmer that is not me, seeing this error for the first time can use to gain an understanding of the underlying system. I consider the message field to be appropriate for a short (one sentence) explanation, a hint as to how this error is frequently raised, or a reference to further reading.
So, as far as I understand your question, I think that the best way to store this 'additional information' that is received from another system is as an InnerException. I don't know Elmah, but if it's worth its salt it will check for InnerExceptions and store them.
I don't understand the question -- you're extending System.Exception, and you already added the Elmah field. That's where it belongs -- as a public property of the exception itself.
Elmah is a http module that records unhandled exceptions.
I guess it's just a limitation of Elmah, since it doesn't store custom fields. I guess I'll have to ask those guys. I have the extra field in there for the response data, but Elmah does not store it.
Related
When writing classes for internal processing in .Net, I often use ArgumentException to indicate something is wrong with the given data and it can't be processed. Due to the nature of the program, the text I put in these exceptions is sometimes relevant to the user, and so it often gets shown on the UI.
However, I noticed that ArgumentException specifically overrides the Message property to append its own string to indicate which argument caused the exception. I don't want this extra text polluting the message, since the actual argument name is internal processing info that really doesn't need to be shown to the user, and the fact it adds a line break, and that it is localised, messes up the formatting of the message I show on the UI. The only way to get around this is to not give the exception the actual argument name, but I don't want to sabotage my own debugging / logging by removing that information, either.
I could use my own exception class, of course, but since a lot of these methods are for compression and decompression of proprietary file formats in old DOS games, and I want these methods to both be documented on a wiki and be generally easily usable by anyone else, I'd prefer keeping them portable and avoid reliance on other external classes. And, as a side note, subclassing ArgumentException would of course give the same issue.
The original source:
public override String Message
{
get {
String s = base.Message;
if (!String.IsNullOrEmpty(m_paramName)) {
String resourceString = Environment.GetResourceString("Arg_ParamName_Name", m_paramName);
return s + Environment.NewLine + resourceString;
}
else
return s;
}
}
(from referencesource.microsoft.com)
Since this actually overrides the Message property, there seems to be no normal way to get to the real message that's stored internally. Splitting on a line break seems messy and potentially unreliable depending on localisation differences (and the message I give it might potentially have line breaks already), and using reflection for this seems rather messy. Is there a clean way to recover the original message?
(Posting this here with solution for documenting reasons, since this behaviour really frustrated me when I encountered it)
Since I didn't want to dig into reflection, I figured a good way to get the original data without the associated class behaviour would be to serialize it. The names of the properties in the serialised info are very straightforward, and can be accessed without the ArgumentException getter mangling it with its own additions.
The code to accomplish this turned out to be pretty straightforward:
public static String RecoverArgExceptionMessage(ArgumentException argex)
{
if (argex == null)
return null;
SerializationInfo info = new SerializationInfo(typeof(ArgumentException), new FormatterConverter());
argex.GetObjectData(info, new StreamingContext(StreamingContextStates.Clone));
return info.GetString("Message");
}
I'm sure I've seen this in various exception messages in the framework. I checked the following pages from the MSDN library but could not find much guidance for the message contents:
Exception Throwing
Error Message Design
Exception.Message Property
The only part in the first page that could explain it is this text:
Do not disclose security-sensitive information in exception messages
without demanding appropriate permissions.
It's the the ArgumentException thrown by Dictionary<TKey, TValue>.Add method that reminded me of this issue. It looks like this:
System.ArgumentException : An item with the same key has already been added.
Why does it not look something like this?
System.ArgumentException : An item with the same key(123) has already been added.
This assumes 123 is the TKey value, basically any format with the TKey value is what I would thing would be useful to track down an error while debugging.
Is there a known reason why this is not included?
Would it be considered bad practice to re-thrown the argument exception with the key in the message? I had considered making my own exception subclass but I think this is a case where using a built in exception class seems like a better option.
As a rule of thumb, exceptional situations in frameworks want to avoid creating new exceptional situations. To format the message like this:
System.ArgumentException : An item with the same key(123) has already been added.
One would have to assume there is a valid implementation of toString on the key parameter. But what if it is null? Or if it is a custom key that throws a new exception in its toString? Or even some idiot implemented a toString method that throws a random exception 1 out of 10 times? What if the internal exception was caused by an out of memory situation and the conversion would just trigger it again? It would give more unpredictable results than just reporting what it is sure to be able to report.
It looks like a security precaution. The program could be working with security-sensitive data, which it takes care not to write into log messages or reveal through the UI. But, oops, there is a problem and an unhandled exception goes off, where some default handler displays or logs pieces of that sensitive information because it was included in the exception text.
My software uses Try Catch to catch errors; recently an error occurred (a timeout connection to the database) and a Messagebox.Show() pops up alerting the user of the issue. The end users of this in house software are not IT literate at all. The lady who received this message asked me with whom she had lost a connection with (I honestly think she thought it was a spiritual 'connection' since she looks like a hippy).
So what I would like to do is simplify the error messages.
Things I've considered:
I could check/compare the ex.Message string to a list of strings I want to cater for and if it matches one I will display the simplified version. IMO, not realistic.
I then thought having multiple catches, and if it's of a certain type, to display the simple message. But how messy is my code going to be! Not only that, it's also probably going to end up with misleading messages as not all (eg) TimeOutExceptions are the same.
Or, I have to try and write my own Exception type to cater for this.
I then though it would be really handy if each .NET exception had an associated ID - that way, I could write a nice case statement with each ID and my own nice and easy to ready/understand message.
Has anyone else considered this before and did they find any suitable arrangements. Or is it better to just put a message on screen saying "Error - an email has been sent to the software vendor...")?
You should never display Exception.message to end users. This is informational text that helps to identify the kind of error.
Anytime you catch the exception, you are supposed to handle it properly or rethrow/throw another. If you are at the point of code that handles the exception by displaying some error message, you should be able to infer the context properly from the Exception itself. You can use proper exception types to create some basic exception domain (DatabaseException, CommunicationException) and the use error codes that discriminate the exception further within its domain.
You can use Data property which belongs to Exception class and is type of IDictionary, thus serving as Exception state bag. You can then store here something like 'ERR_CODE' = CONSTANT and have some single point of exception handling that will check the error code and if it's present, handle the exception with some user friendly output.
You can even register global exception handler within current AppDomain to catch any uncaught exception and display some message. This is common practice, but you must be aware that this approach breaks the natural code-flow and if such thing happens, you are left with handled exception but non-caught exception flow (you didn't handle the exception on the caller site which then doesn't know that the call failed and may behave unpredictable). So use this approach only by printing some user friendly message and ending application or terminating current Usecase.
If ever you write code like catch (Exception ex) then you are doing something wrong. You should always catch specific exceptions for coding situations that are exceptional.
Have a read of Eric Lippert's "Vexing exceptions" blog entry.
Catching exceptions and just displaying the message is in the "boneheaded" category of exceptions. You should never have them.
Instead you should only have exceptions of the other three types expounded by Eric. And you should catch the specific exception type involved, not the generic Exception type.
If you catch specific exceptions then you can present a very reasonable message to the end user - even providing information about how to solve the problem.
Better still, without all the generic exception catching your code will be easier to debug, cleaner and more terse. The major predictor for bugs in code is the actual lines of code you write. Write less code and have less bugs.
So my suggestion is change your code design and handle the exceptions appropriately.
In general, you will need to handle the exception by its type (e.g. catch (SomeSpecificException))
Certain derived exception types do have additional codes, e.g.
e.g. SqlException has a Number property which can be used for control flow / information
catch (System.Data.SqlClient.SqlException sqlEx)
{
if (sqlEx.Number == 1205) // Deadlock
...
if (sqlEx.Number == -2) // = TimeOut
...
// etc.
}
Edit
Actually, System.Exception does have a protected HRESULT property. See How do I determine the HResult for a System.IO.IOException? and
How to get Exception Error Code in C#
Although it isn't directly accessible, you can retrieve it via Marshal.GetHRForException(ex). Different exceptions have different HRESULTs, e.g.
System.Exception : HRESULT COR_E_EXCEPTION (0x80131500)
System.SystemException : HRESULT COR_E_SYSTEM (0x80131501)
That said, as per other answers, catching specific exceptions is still the preferred mechanism IMO - presumably the HRESULT mechanism is a COM hangover.
You should handle and provide meaningful message for those exceptions only you anticipate might arise in your code and the exception can be handled. Any exception you do not anticipate, display a generic message and log the message to log file or event log. You may also want to setup a policy for the unhandled/unexpected exceptions such that display message to contact support and exit application.
I was wondering what kind of exception should one throw for missing data. For example if an xml node doesn't contain data. It would be easy to "throw new Exception(...)" but this is not recommended. Another option would be to create a new exception class like MissingDataException or InvalidDataException but isn't there a built-in exception class for this case?
As a rule of thumb, check the existing .NET framework exceptions for a suitable exception to throw before deriving your own. To answer your question directly, there is no "missing data" exception currently available to throw, but that doesn't mean there aren't suitable exceptions to cover your situation.
In your case, the humble InvalidOperationException may be suitable; this exception is thrown when you call a method on an object, but the object's state is not appropriate for the operation. Examples of this include calling methods on a closed stream and an enumerator that has passed the end of the collection. If the XML data is the internal state of an object, and a method call has discovered the bad data, InvalidOperationException is a good candidate.
If you are passing your XML data to a method, an ArgumentException, or one of its derivatives may be an appropriate choice. There is a small family of these exceptions, all indicating that an argument passed to a method is not as the method expected.
You will only want to create a custom exception when you want the exceptional circumstance to be handled differently from other exceptions. If you do choose to create your own exception, be sure to derive it from a higher exception than Exception, so that the nature of the exception is implied by the base class.
There is also System.Data.ObjectNotFoundException class which you may consider.
Update: As of Entity Framework 6, this exception class' fully qualified name is System.Data.Entity.Core.ObjectNotFoundException.
See this question for further details on EF5->EF6 namespace changes.
Do not call "throw new Exception", because you don't know how to handle the exception.
Define your own exception. Be more specific, such as XMLDataMissingException. Then you can give a meamingful message to user or log it.
For a general missing data scenario, where the data is referenced by a unique ID, then the KeyNotFoundException might be appropriate - e.g.
throw new KeyNotFoundException($"Expected record for key {key} not found.");
It is in the System.Collections.Generic namespace.
You can use System.Xml.XmlException.
Edit : Even if System.Xml.XmlException could fit, I think you should define your own exception, as it would be more precise, and you could describe what kind of data is missing : an id, a date, etc.
As a rule of thumb you should throw exceptions in Exceptional Circumstances. If the data in question adversely affects the object’s state or behaviour then throw a custom exception. An alternative approach might involve some kind of validator that fires events which your client handles gracefully, for example, report the error to end-user or insert default values.
I had a similar problem you described in which I had 2 clients (call them A & B) reading and modifying a single xml file. Client A deleted node X then Client B attempted to update node X. Clearly, updating a node that no longer exists is a problem. To solve this problem I took inspiration from SQL Server which reports the number of rows affected by an UPDATE statement. In this particular case I raised the UpdateNode event as normal with a number of rows affected property set to zero.
InvalidDataException actually exists. It's in the System.IO namespace.
MSDN
IMO, it's more appropriate than ArgumentException or another boneheaded exception type.
Also, I strongly suggest that you use messages to describe which data is missing, what was the expected value, etc...
throw new Exception("my message"); (or other built in Exception) is often the correct approach. The alternative is an explosion of Exception classes that may only get used once.
If new Exceptions are warranted they should be created in the context of the domain, not the problem.
How have you used the Exception.Data property in C# projects that you've worked on?
I'd like answers that suggest a pattern, rather than those that are very specific to your app.
The exception logger I use has been tweaked to write out all the items in the Data collection. Then for every exception we encounter that we cannot diagnose from the exception stack, we add in all the data in that function's scope, send out a new build, and wait for it to reoccur.
I guess we're optimists in that we don't put it in every function, but we are pessimists in that we don't take it out once we fix the issue.
Since none of the answers include any code. Something that might useful as an addition to this question is how to actually look at the .Data dictionary. Since it is not a generic dictionary and only returns IDictionary
foreach(var kvp in exception.Data) the type of kvp will actually be object unhelpfully. However from the MSDN there's an easy way to iterate this dictionary:
foreach (DictionaryEntry de in e.Data)
Console.WriteLine(" Key: {0,-20} Value: {1}",
"'" + de.Key.ToString() + "'", de.Value);
I don't really know what the format argument , -20 would mean, maybe Take(20)? Digressing... this code can be very helpful in a common error logger to unwind this data. A more complete usage would be similar to:
var messageBuilder = new StringBuilder();
do
{
foreach (DictionaryEntry kvp in exception.Data)
messageBuilder.AppendFormat("{0} : {1}\n", kvp.Key, kvp.Value);
messageBuilder.AppendLine(exception.Message);
} while ((exception = exception.InnerException) != null);
return messageBuilder.ToString();
I have used it when I knew the exception I was creating was going to need to be serialized. Using Reflector one day, I found that Excepion.Data gets stuck into and pulled from serialization streams.
So, basically, if I have properties on a custom exception class that are already serializable types, I implement them on the derived class and use the underlying data object as their storage mechanism rather than creating private fields to hold the data. If properties of my custom exception object require more advanced serialization, I generally implement them using backing private fields and handle their serialization in the derived class.
Bottom line, Exception.Data gives you serialization for free just by sticking your properties into it -- but just remember those items need to be serializable!
I've used it to capture information about the state at the time of the Exception from the enclosing scope as the Exception travels up the stack. Items like the filename that caused the Exception, or the value of some ID that will help track down the problem.
At the top most level in a web application I also tend to add much of the Request information like the RawUrl, the cookies, the Referrer, ...
For more details here's my blog on the topic:
Rather than waiting for problems to happen I add this code in wherever an Exception can occur that's related to something external, e.g. a file name, or an URL that was being accessed, ... In other words, any data that will help repro the problem.
I just tried to use it and found out that it is not very useful for my purpose - so I am not using it.
The most important part of the stack trace is to be able to tell what happened. The method name and line number are great, but you often need to see value of relevant variables in the context of the exception. I thought that was the whole point of the Data. But - you have to see it for it to be useful.
In my case, I control the code around the caught exception but not the code that logs it. So, for me Data is useless if it is not being automatically printed out in the stack trace. I might as well log the values myself rather than add them to the Data. Or, somehow modify the message to add the values in it, so that it gets logged but without losing the original stack trace with line numbers and method names.