4

I have a block of code to handle exceptions in my application, which uses an if/else block to obtain the message content.
My code is as follows:

// define variable to hold exceptions...
var exceptionMessage = new StringBuilder();  
// based on the exception type...  
if (expType == typeof(EntityValidationException))  
{  
    // append the relevant message to the text...  
    exceptionMessage.Append(exception.InnerException.Message);  
}  
else if (expType == typeof(ValidationException))  
{  
    // This is the type of error generated when entities are validated  
    var validationException = (ValidationException)exception;  
    exceptionMessage.Append(validationException.InnerException.Message);  
}  
else if (expType == typeof(DomainSecurityException))  
{  
    // These are security breaches  
    var domainSecurityException = (DomainSecurityException)exception;  
    exceptionMessage.Append(domainSecurityException.InnerException.Message);  
}  
else if (expType == typeof(DomainInternalMessageException))  
{  
    // These are the type of errors generated a System.Exception occurs and is  
    // converted by the exception handling policy to a more friendly format  
    var domainInternalMessageException = (DomainInternalMessageException)exception;  
    exceptionMessage.Append(domainInternalMessageException.ExceptionMessage);  
}
else  
{  
    exceptionMessage.AppendFormat(ErrorMessagesRes.Standard_Error_Format, "Unknown error", exception.InnerException.Message);   
}  
// this shows the message as an alert popup...  
this.DisplayJavascriptMessage(exceptionMessage.ToString());

This has been improved from the original version, but just want to see if there is a neater, more re-usable solution to this code.
Thanks in advance
Martin

ba__friend
  • 5,783
  • 2
  • 27
  • 20
Martin S
  • 211
  • 1
  • 4
  • 18

5 Answers5

5

Assuming that this is a routine which gets passed an exception object (and is not directly involved in a try catch block) and assuming the "exception" object derives eventually from Exception, you could concise your code a bit to do

// define variable to hold exceptions...
            var exceptionMessage = new StringBuilder();

            // based on the exception type...  
            if (exception is EntityValidationException || exception is ValidationException || exception is DomainSecurityException)
            {
                // append the relevant message to the text...  
                exceptionMessage.Append(exception.InnerException.Message);
            }

            else if (expType == typeof(DomainInternalMessageException))
            {
                // These are the type of errors generated a System.Exception occurs and is  
                // converted by the exception handling policy to a more friendly format  
                var domainInternalMessageException = (DomainInternalMessageException)exception;
                exceptionMessage.Append(domainInternalMessageException.ExceptionMessage);
            }
            else
            {
                exceptionMessage.AppendFormat(ErrorMessagesRes.Standard_Error_Format, "Unknown error", exception.InnerException.Message);
            }
            // this shows the message as an alert popup...  
            this.DisplayJavascriptMessage(exceptionMessage.ToString());
Nikhil
  • 3,304
  • 1
  • 25
  • 42
2
    var exceptionMessage = new StringBuilder();  

    try
    {
    }
    catch(EntityValidationException exc)
    {  
        exceptionMessage.Append(exc.InnerException.Message);  
    }  
    catch(ValidationException exc)  
    {  
        exceptionMessage.Append(exc.InnerException.Message);  
    }  
    ....

Make sure the catch blocks come in proper order from least generic to most generic.

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • It's for a web application, and we want to handle the errors, pass the exception message to a log file, and show a simple error page, rather than the application bomb out with a error stack. It works, but whilst reviewing the code, i wondered if it could be improved. – Martin S Mar 01 '11 at 11:28
  • 1
    @thecoop - the code in question doesn't show what is being thrown – Jakub Konecki Mar 01 '11 at 11:29
  • The original exception source should be wrapped with this try block. – Shimmy Weitzhandler Mar 01 '11 at 11:29
  • @Jukub Konecki - thaks, but the exception is being passed in, so the try/catch block won't work. I'm using the exception to log and convert it to a friendlier message. – Martin S Mar 01 '11 at 11:30
  • @Jukub Konecki - Sorry. At present, each aspx page event uses a try/catch block, and any exceptions are passed to this procedure. This then attempts to find out the type and get the message details. I don't want to change the way it handles as we are too far into development now, but am just trying to make the code more readable and re-usable going forward. Thanks for all the suggestions so far. – Martin S Mar 01 '11 at 11:35
2
public static Exception On<T>(this Exception e, Action<T> action)
{
    if(e is T)
        action((T)e);

    return e;
}

exception.
    On<ValidationException>(e => exceptionMessage.Append(e.InnerException.Message)).
    On<DomainInternalMessageException>(e => ...);
Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
  • @Martin S: Make that `On` method a member of some static class and rewrite your exception handling code with this big-ass chain of method calls. – Anton Gogolev Mar 01 '11 at 11:50
  • OK, but I get an error trying to cast expression of type 'System.Exception' to type 'T' with the on method. – Martin S Mar 01 '11 at 12:02
  • I've tried to implement @Anton's code, but get the cast error in the method; am unsure how to handle where I want to do more than just append to a stringbuilder object within the On method, and also can I simply pass On into the chain to deal with the else? – Martin S Mar 01 '11 at 14:01
1

Whenever i see those if else if statements i think this must be done easier. In some cases the switch statement can help, but as this question already stated, it is not possible to switch on Type.

So another workaround i commonly use is some kind of Dictionary<Type, something>. Where something depends on what i'd like to do. The maybe best matching construct for your case would something like Dictionary<Type, Func<Exception, string>> which could be used in your case something like this:

Dictionary<Type, Func<Exception, string>> _FunctorsForType;

private void InitializeFunctorsForType()
{
    _FunctorsForType = new Dictionary<Type, Func<Exception, string>>();

    // Add a normal function
    _FunctorsForType.Add(typeof(ArgumentException), (Func<Exception, string>)ForArgumentException);

    // Add as lambda
    _FunctorsForType.Add(typeof(InvalidCastException), (ex) =>
        {
            // ToDo: Whatever you like
            return ex.Message;
        });
}

private string ForArgumentException(Exception ex)
{
    var argumentException = ex as ArgumentException;

    if (argumentException == null)
    {
        throw new ArgumentException("Exception must be of type " + typeof(ArgumentException).Name);
    }

    // ToDo: Whatever you like
    return ex.Message;
}

private void Usage(Type type)
{
    Func<Exception, string> func;

    if (!_FunctorsForType.TryGetValue(type, out func))
    {
        throw new ArgumentOutOfRangeException("Exception type " + type.Name + " is not supported.");
    }

    var message = func(new NullReferenceException());

    // ToDo: Whatever you have to do with your message
}

So with this construction you don't have to put all your intelligence into a big if-else statement. Instead you can put them in separate functions (maybe in different classes) to get a better organization of how to handle each type you like to support.

Community
  • 1
  • 1
Oliver
  • 43,366
  • 8
  • 94
  • 151
0
string exceptionMessage;
if (expType == typeof(EntityValidationException) || 
    expType == typeof(ValidationException) ||
    expType == typeof(DomainSecurityException))
  exceptionMessage = exception.InnerException.Message;
else if (expType == typeof(DomainInternalMessageException))  
 exceptionMessage = ((DomainInternalMessageException)exception).ExceptionMessage;
else  
 exceptionMessage = string.Format(ErrorMessagesRes.Standard_Error_Format, "Unknown error", exception.InnerException.Message);  

this.DisplayJavascriptMessage(exceptionMessage);

A little compressed, and without comments.

Cine
  • 4,255
  • 26
  • 46