I have a standalone application that does data checking of flat files before they are imported into a SQL database.
In a context like this, does it make sense to throw a System.Data.ConstraintException? (The example is contrived.)
if(_keys.ContainsKey(key))
{
throw new ConstraintException(string.Format("Uniqueness violated! " +
"This unique combination of '{0}' already found on line {1}",
GetUniquenessColumnList(), _keys[key] ));
}
ConstraintException's documentation states that it "represents the exception that is thrown when attempting an action that violates a constraint."
Is there a problem with using the built-in exception this way? Is there a better one to use? Should I build my own, even though this exception seems tailor-made to my situation?
I think you've answered your own question
...this exception seems tailor-made to my situation?
Why reinvent the wheel?
EDIT:
Check out this MSDN article: Choosing the Right Type of Exception to Throw
Consider throwing existing exceptions residing in the System
namespaces instead of creating custom exception types.
...
Do not create and throw new exceptions just to have your team's exception.
No, there's no problem with doing that. No need to create a new exception if a suitable one already exists.
Related
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.
Consider the case where a configuration (a property, in my case) is null.
public Configuration {get;set;}
if (configuration == null)
{
throw NullReferenceException("Blah blah blah..");
}
But, I read somewhere, "Dont ever throw a null reference exception in your code. NullReferenceException is a runtime exception and should only be raised by the runtime".
If it had been a argument of a function, I thought I would use a ArgumentNullException.
So, what should be the exception in this case? And speaking in general, what exceptions should be thrown at what situations? Googled this but no satisfying answers.
InvalidOperationExceptions states - The exception that is thrown when a method call is invalid for the object's current state ,which isn't a bad fit I suppose? I agree that a null reference isn't what you should throw.
here's another list of common exceptions.
The advice is correct, because a null reference exception doesn't say anything about what's actually wrong.
If the value isn't allowed to be null, then you should try to find an exception that describes what's wrong. The problem isn't that the reference is null, but the underlying reason why the reference is null.
If you can't find any exception class that is close enough, you could for example create your own ConfigurationMissingException exception.
InvalidOperationException
The exception that is thrown when a method call is invalid for the object's current state.
Which sounds like your situation.
Basically, if it's not argument related, and you want to throw a built-in exception, your choices usually come down to one of two exceptions. If you'll never be able to honor the request, NotImplementedException is appropriate. But if it's a matter of configuration or state, InvalidOperationException fits the bill.
You should throw no exceptions at what case. It only uses if happens something unexpected like you try set some null value to Configuration.
But if Configuration can be null and it already is, you should handle it out in other way.
I think there are actually three cases here:
Firstly, can this happen as a result of the user of the class doing things wrongly? Did they forget to call or set something first (i.e. is there a temporal dependency that they violated)?
If so, then I think the appropriate exception is either an InvalidOperationException, with a Message that describes how to fix the problem, or perhaps you might want to specify a Code Contract as described below.
Secondly, can this only happen due to a logic bug in the class? In other words, should it be impossible for this to happen no matter how the user of the class uses its public methods and properties?
If so, then if you are using Code Contracts you can declare this to be the case by stating:
Contract.Assume(configuration != null);
I find this to be much better. However, the exception thrown by a violation is uncatchable other than if you catch Exception. This is deliberate, and the right choice IMO.
If you're not using code contracts, then you're stuck with throwing InvalidOperationException.
Thirdly, if this exception arises naturally because of external factors outside the program's control, you should probably write a custom exception type for it if there is no existing one which matches the problem. However, for this particular example it seems unlikely that this is the case. I would expect it to be handled elsewhere.
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.
For this method, XmlSerializer.Deserialize, what kinds of exception may be thrown? XmlException? InvalidOperationException? I did not find any exception description information from this method. My question is what kinds of exception could be thrown from this method?
http://msdn.microsoft.com/en-us/library/dsh84875.aspx
I am using VSTS2008 + C# + .Net.
thanks in advance,
George
Looks like primarily InvalidOperationException.
If you go through the documentation for each of the overloads, it will give you more details. For example, see XmlSerializer.Deserialize Method (XmlReader)
The InvalidOperationException will contain more details about the specific error in its InnerException property.
Edit:
The XmlSerializer.Deserialize Method (XmlSerializationReader) can throw a NotImplementedException, but it is an internal API and is not meant to be used by your code, so don't worry about it.
Edit 2:
This code:
var ms = new System.IO.MemoryStream();
var deser = new System.Xml.Serialization.XmlSerializer(typeof(string));
deser.Deserialize(ms);
throws:
System.InvalidOperationException: There is an error in XML document (0, 0). ---
System.Xml.XmlException: Root element is missing.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
... <snip> ...
So it really looks like the framework will always throw an InvalidOperationException.
Really, unless you're worried about mistakenly catching exceptions like ThreadAbortException, you are probably safest catching all exceptions...
Edit 3:
Using Reflector: The Deserialize(stream) method reads the stream using an XmlTextReader and calls the XmlSerializer.Deserialize Method (XmlReader, String). That method throws an InvalidOperationException on error (according to the docs).
Edit 4:
Deserialize(stream) can also throw a NullReferenceException if stream is null, because it calls the XmlTextReader(Stream) constructor.
Exceptions from the XmlSerializer
Diagnosing the source of these problems can be tricky at first,
because the exceptions from the XmlSerializer do not seem to provide a
lot of information about the cause of their occurance; at least, they
do not provide the information in a spot where developers typically
would look.
In most cases, Serialize, Deserialize and even the XmlSerializer
constructor throw a rather generic System.InvalidOperationException
when an error occurs. This exception type can occur in many places in
the .NET Framework; it is not specific to the XmlSerializer at all. To
make matters worse, the exception's Message property only yields very
generic information, as well.
This and other very handy tips about exceptions in the XmlSerializer can be found on the document Troubleshooting Common Problems with the XmlSerializer.
George, because there is no exception contract in .NET, the best practice is to catch any specific exceptions that you may want to do special processing for, but to also have a catch-all exception handler that handles all failures appropriately.
I have implemented several XML serialization solutions using the built-in .NET serialization, and have in all cases just used a catch-all except block, which walks the innerexceptions of the caught exception, adding all error messages and exception class types to a string message. Doing it like that has always provided enough information to debug any serialization issues.
On a related note, what I normally do is to add a debug log level which logs the full xml to my application's log, so that I can inspect it to try and figure out what when wrong when debugging a serilization issue.
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.