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.
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");
}
This is not trying to find a method name using Method Info. I already have the method name.
The business wants a log with all the exceptions recorded. They also want each exception to have some sort of logical ID. So ops can search the documentation for ID "BusinessRule2319Violated". We also have more general type failures of course "RegisteringClientFailed".
For the specific Exceptions like the violation of a business rule we populate the Data property with the ID. Not a problem. But for more general exceptions like something unaccounted for in Registering the client threw an exception I don't want to pepper my code with hundreds / thousands of try / catches to assign a unique code.
I am thinking of decorating methods with a kind of attribute like [DefaultExceptionCodeAttribue("RegisteringClientFailed") then in the Middleware or some global exception handler crawl the e.StackTrace and find the attribute.
I've gotten as far as code that find the name of the class and method from the StackTrace, but I can't figure out how to turn that into a MethodInfo to start checking attributes.
I can sometimes use Type.GetType(string) and get something, but other times it returns null, for the same type, depending on where I call it.
I feel like I am just missing an easy way to do this.
Thanks for your time.
I am building a logging control for a C# project and would like to be able to call it with the name of the current source code File, Line, Class, Function, etc. PHP uses "magic constants" that have all of this info: http://php.net/manual/en/language.constants.predefined.php but I don't see anything like that in the C# compiler language.
Am I looking for something that doesn't exist?
Using the StackTrace/StackFrame classes, you can have your control find out where it's been called from, rather than passing it that information:
private static StringBuilder ListStack(out string sType)
{
StringBuilder sb = new StringBuilder();
sType = "";
StackTrace st = new StackTrace(true);
foreach (StackFrame f in st.GetFrames())
{
MethodBase m = f.GetMethod();
if (f.GetFileName() != null)
{
sb.AppendLine(string.Format("{0}:{1} {2}.{3}",
f.GetFileName(), f.GetFileLineNumber(),
m.DeclaringType.FullName, m.Name));
if (!string.IsNullOrEmpty(m.DeclaringType.Name))
sType = m.DeclaringType.Name;
}
}
return sb;
}
(I used this code to get the call stack of the currently executed method, so it does more than you asked for)
The StackTrace/StackFrame classes will give you quite a bit of this, though they can be quite expensive to construct.
You can ask the system for a stack trace, and you can use reflection. Details are coming.
__LINE__
__FILE__
__DIR__
__FUNCTION__ (does not really exist in C#)
__CLASS__
__METHOD__
__NAMESPACE__
This is a start:
http://www.csharp-examples.net/reflection-callstack/
http://www.csharp-examples.net/reflection-calling-method-name/
Assembly.GetExecutingAssembly().FullName
System.Reflection.MethodBase.GetCurrentMethod().Name
You will get better information in Debug (non-optimized) build. PhP might always have access to all that stuff, but it ain't the fastest gun on this planet. Play with it and let me know what is missing.
There are methods to get this type of data. It depends on what data you want.
__CLASS__ : If you want the current classname you'll need to use reflection.
__LINE__ : I'm not sure what "The current line number of the file" means, I'll take a guess and say it's how many lines in the file. That can be done by opening the file and doing a line count. This can be done via the File class, the FileInfo class may also work.
__DIR__ :Getting the directory of the file is done by using the DirectoryInfo class.
__FUNCTION__ and __METHOD__: Function name (method name), this can be retrieved via reflection.
__NAMESPACE__ :Namespace an be retrieved via reflection
Using Type, the best you can really do is get information about the current class. There is no means to get the file (though you should generally stick to one class per file), nor line number, nor function using Type.
Getting a type is simple, for example, this.getType(), or typeof(MyClass).
You can get the more specific details by generating a StackTrace object and retrieving a StackFrame from it, but doing so repeatedly is a bad idea.
I think a more important question is perhaps: why do you need them? For trace debugging, your output is supposedly temporary, so whether it reflects an accurate line number or not shouldn't matter (in fact, I rarely ever include a line number in trace debugging). Visual Studio is also very useful as a true step debugger. What do you really need File, Class, Function, and Line Number for?
Edit: For error checking, use exceptions like they're meant to be used: for exceptional (wrong) cases. The exception will generate a stack trace pointing you right at the problem.
Many of the previous responders have provided excellent information; however, I just wanted to point out that accessing the StackFrame is exorbitantly expensive and probably shouldn't be done except for special cases. Those cases being an extremely chatty verbose mode for debugging corner cases or error logging and for an error you probably already have an Exception instance which provides the StackTrace. Your best performance will be as Bring S suggested by using Type. Also as another design consideration logging to the console can slow your application down by several orders of magnitude depending on the volume of data to display. So if there is a console sink having the writer operating on a worker thread helps tremendously.
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.
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.