views:

1333

answers:

10

Here's a standard scenario:

if(string.IsNullOrEmpty(Configuration.AppSettings("foobar")))
   throw new SomeStandardException("Application not configured correctly, bozo.");

The problem is, I am not entirely certain which exception SomeStandardException should be.

I perused the 3.5 Framework and found two likely candidates: ConfigurationException and ConfigurationErrorsException.

System.Configuration.ConfigurationException

The exception that is thrown when a configuration system error has occurred.

Remarks

The ConfigurationException exception is thrown if the application attempts to read or write data to the configuration file but is unsuccessful. Some possible reasons for this can include malformed XML in the configuration file, file permission issues, and configuration properties with values that are not valid.

Note:

The ConfigurationException object is maintained for backward compatibility. The ConfigurationErrorsException object replaces it for the configuration system.

This exception actually sounds perfect for what I need, but it's been marked obsolete, so, ixnay on atthay.

This brings us to the thoroughly puzzling ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

The current value is not one of the EnableSessionState values.

As you can see, its documentation is completely useless. (It's that way in both local and online help.) An examination of the class itself shows that it's drastic overkill for what I want.

In a nutshell, I need a standard exception that should be thrown when an application configuration setting is missing or contains an invalid value. You'd think the Framework had such an exception baked into it for applications to use. (It apparently did, but it was marked obsolete, and was replaced by something much larger in scope.)

What solutions, if any, are you guys using for this, and am I going to have to suck it up and roll my own exception for this?

Edit Addenda

Some have asked whether or not I could provide a default value, and continue. In certain cases, yes, and in those cases, the exception would not be thrown. However, for certain settings, this won't apply. For instance: database server names and credentials, authentication servers, and paths to installed third party applications.

It is also worth noting that the application I'm primarily working on is a console application running in batch mode, and I want it to throw an exception that is caught by the main method and logged appropriately if the thing isn't appropriately configured. (It's legacy code I've inherited, and currently just assumes everything's peachy.)

A: 

I'd suck it up and roll my own... but before you do that, Is it possible to have the system assume a default value for this configuration setting? I generally attempt to do that for every setting that might get missed bu Ops Management folk... (or perhaps I should say, for as many settings as possible - for some it is clearly not appropriate to have the system make a default decision...)

in general a custom exception is not a lot of effort... here's an example...

[Serializable]
public class MyCustomApplicationException : ApplicationException
{
    #region privates
    #endregion privates

    #region properties
    #endregion properties

    public MyCustomApplicationException (string sMessage,
        Exception innerException)
        : base(sMessage, innerException) { }
    public MyCustomApplicationException (string sMessage)
        : base(sMessage) { }
    public MyCustomApplicationException () { }

    #region Serializeable Code
    public MyCustomApplicationException (
       SerializationInfo info, StreamingContext context)
        : base(info, context) { }
    #endregion Serializeable Code
}
Charles Bretana
MSDN: ... an application that needs to create its own exceptions, [...] derive custom exceptions from the Exception class. It was originally thought that custom exceptions should derive from the ApplicationException class; however in practice this has not been found to add significant value.
Gaspar Nagy
Yes, I think it was because the MS programmers who coded the framework derived numerous CLR exceptions from ApplicationException, thus destroying the significance of the distinction.. I still do it though, as I see no harm in it...
Charles Bretana
A: 

You could try inheriting off the XML Exception, or just using it.

StingyJack
+4  A: 

You're not limited in your exception-throwing to existing exceptions in the Framework. If you do decide to use existing exceptions, you don't absolutely have to follow the documentation to the letter. The documentation will describe how the framework uses a given exception, but doesn't imply any limitation on how you choose to use/reuse an existing exception.

It's your application- as long as you document it and clearly indicate the exception that will be thrown in the specific case of a missing configuration value, you can use any exception you like. If you do want a very specific indication of a missing value, you might consider writing your own ConfigurationSettingMissing exception:

public class ConfigurationMissingException : ConfigurationErrorsException
{}

EDIT: Writing your own exception in this case carries the added benefit of guaranteeing that there will never be any confusion regarding where the exception is coming from- the framework, or your application. The framework will never throw your custom exceptions.

UPDATE: I agree with the comments, so I have changed the subclass to ConfigurationErrorsException from Exception. I think it's generally a good idea to subclass custom exceptions from existing Framework exceptions where possible, avoiding the Exception class unless you need an application-specific exception.

Dave Swersky
I disagree somewhat. If you're going to use an existing exception, it should be used EXACTLY as the documentation says its used, or else you'll confuse those who come after you. If you're going to do something different, just create your own exception, like you said.
Robert C. Barth
I disagree. Unless you have a scenario for catching your custom exception, unlikely in the case of a configuration error, it's better to reuse an existing Type (ConfigurationErrorsException). And if you do create a custom Type, I'd derive it from a related Type such as ConfigurationErrorsException.
Joe
Dave Swersky
+4  A: 

Personally, I'd use InvalidOperationException, as it's a problem with the object state - not the configuration system. After all, shouldn't you allow these settings to be set by code and not config as well? The important part here is not that there was no line in app.config, but that a required piece of info was not present.

To me, ConfigurationException (and it's replacement, ConfigurationErrorsException - despite the misleading MSDN docs) are for errors in saving, reading, etc. of Configuration.

Mark Brackett
+1  A: 

The ConfigurationElement class (which is the base class of many config-related classes, like ConfigurationSection) has a method called OnRequiredPropertyNotFound (there are other helper methods too). You can maybe call those.

The OnRequiredPropertyNotFound is implemented like this:

protected virtual object OnRequiredPropertyNotFound(string name) {
    throw new ConfigurationErrorsException(SR.GetString("Config_base_required_attribute_missing", new object[] { name }), this.PropertyFileName(name), this.PropertyLineNumber(name)); }
Gaspar Nagy
A: 

My general rule would be:

  1. If the case of the missing configuration is not very common and I believe I would never want to handle this case differently than other exceptions, I just use the basic "Exception" class with an appropriate message:

    throw new Exception("my message here")

  2. If I do want, or think there's a high probability I would want to handle this case in a different manner than most other exceptions, I would roll my own type as people have already suggested here.

Hershi
+1  A: 

I tend to disagree with the premise of your question:

In a nutshell, I need a standard exception that should be thrown when an application configuration setting is missing or contains an invalid value. You'd think the Framework had such an exception baked into it for applications to use. (It apparently did, but it was marked obsolete, and was replaced by something much larger in scope.)

According to the MSDN documentation on System.Exception (Exception Class, you really shouldn't be throwing exceptions for user input errors, for performance reasons (which has been pointed out by others on Stack Overflow and elsewhere). This seems to make sense as well - why can't your function return false if the user input is entered incorrectly, and then have the application gracefully exit? This seems to be more of a design problem then an issue with which Exception to throw.

As others have pointed out, if you really have to thrown an exception - for whatever reason - there isn't any reason why you couldn't define your Exception type by inheriting from System.Exception.

Matt Jordan
Why exactly would performance matter in this specific scenario? IUC, then the exception is thrown exactly once and the process likely goes down afterwards anyway (of course, after showing a nice pop-up to the user). (to be continued ...)
Andreas Huber
Returning an error code instead of throwing an exception could be painful, because you'd then have to propagate the error information up the call stack yourself. You should use exceptions for relatively rare errors that might be propagated over several stack frames. Both applies here.
Andreas Huber
You missed something: "when an application configuration setting is missing or contains an invalid value", that's not the same as bad user input. This is a basic configuration that's missing. Should be a custom exception and should stop the app from running.
jcollum
In this particular application, it's almost entirely driven by the settings in the configuration file. If the settings aren't in it (where they're encrypted), the application can't continue, and must terminate. An exception is virtually required.
Mike Hofer
This can certainly get into semantics, and your code's structure will obviously dictate the best implementation for your situation. Still, if you had free reign in the design, I would still go with an object to log the error and a graceful exit over an exception, performance being an issue or not.
Matt Jordan
A very good article that discusses the .NET exception model you may want to take a look at is here:http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspxHis portion on performance and trends may be of use - and it honestly may prove or disprove my initial point, depending on your situation.
Matt Jordan
+2  A: 

ConfigurationErrorsException is the correct exception to throw in the situation you describe. An earlier version of the MSDN documentation for ConfigurationErrorsException makes more sense.

http://msdn.microsoft.com/en-us/library/system.configuration.configurationerrorsexception(VS.80).aspx

The earlier MSDN summary and remarks are:

  • The exception that is thrown when a configuration-system error has occurred.
  • The ConfigurationErrorsException exception is thrown when any error occurs while configuration information is being read or written.
Daniel Richardson
+2  A: 

As Daniel Richardson said, ConfigurationErrorsException is the one to use. In general it is only recommended to create your own custom Exception types if you have a scenario to handle them. In the case of configuration errors, which are usually fatal, this is rarely the case so it's usually more appropriate to reuse the existing ConfigurationErrorsException type.

Prior to .NET 2.0, the recommendation was to use System.Configuration.ConfigurationException. ConfigurationException became obsolete in .NET 2.0, for reasons which were never clear to me, and the recommendation changed to use ConfigurationErrorsException.

I use a helper method to throw the exception so that it's easy to change the exception being thrown in one place when migrating from .NET 1.x to 2.0, or if Microsoft decides to change the recommendation again:

if(string.IsNullOrEmpty(Configuration.AppSettings("foobar")))
{
   throw CreateMissingSettingException("foobar");
}

...

private static Exception CreateMissingSettingException(string name)
{
    return new ConfigurationErrorsException(
        String.Format
        (
        CultureInfo.CurrentCulture,
        Properties.Resources.MissingConfigSetting,
        name
        )
        );
}
Joe
A: 

What about System.Configuration.SettingsPropertyNotFoundException?

Laurent