0

I am writing a HttpHandler and as part of my internal design, I throw different exceptions and catch them at the top level in order to determine what status code to set the request to.

I.e. ArgumentException triggers Bad Request
AuthenticationException triggers Unauthorised
OracleException triggers InternalServerError
etc

The problem I've found is that I was using InvalidOperationException to trigger NotFound, but a bug in my code caused me to realise that, of course, some system exceptions inherit from these base system exceptions, which causes unexpected responses.

I.e. I found that ObjectDisposedException inherits from InvalidOperationException, which means that the response returns a 404 instead of 500.

Is there a way to catch just the base exception?

I found this thread which suggests I could do a filter and rethrow, but that seems hacky.

Would I be better off just creating my own exception types to save all this hassle?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Brad Zacher
  • 2,915
  • 18
  • 31
  • 3
    Yes, you should certainly roll your own exception for this specific use case rather than use `InvalidOperationException`. – dursk Mar 10 '15 at 22:01
  • 1
    Definitely do not raise `InvalidOperationException` for something it's not meant. Same applies for any other exception. Make your own exceptions, and base them on `Exception`. Just make sure you pass the original exception as internal exception when you throw your own exceptions in order to maintain call stack. I don't know why you got a downvote, it's a legit and very common mistake. – bokibeg Mar 10 '15 at 22:03
  • @mattm @bokibeg thank you, I probably should have read the doco as to what .NET defines ``InvalidOperationException`` to be. I'll define my own exceptions and wrap any caught exceptions in them. – Brad Zacher Mar 10 '15 at 22:26
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 10 '15 at 22:50

3 Answers3

2

If you only want to pass the HTTP result code (and maybe error message line) to the client, then I recommend you create a single custom exception:

public class MyCustomException : Exception { // Or maybe InvalidOperationException
    public int StatusCode {get;set;}
    public string Status {get;set;}
}

etc.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • This is neat idea, I always forget that you can add more properties to exceptions! However I think I prefer having a set of custom exceptions. Whilst it adds a bit of code overhead, IMO it looks cleaner in code (``throw BadRequestExeption("msg")`` as opposed to ``throw HttpErrorException(400, "msg")``) – Brad Zacher Mar 10 '15 at 23:36
  • 1
    You should minimize the number of custom exception classes you create. Especially in this case, where they are all the same. You could create a set of factory methods to create the particular kinds, and besides, you're talking about two parameters rather than one. – John Saunders Mar 11 '15 at 00:42
  • In my head I always think of exceptions as a separate beast, and forget that they're just classes. I preferred separate named classes as it is easier to get meaning from (rather than the status codes), but the idea of factory functions is great as it allows for a single exception class with the obfuscation of named calls. I've implemented that instead. If you could add that part to your answer, I'll mark it as accepted. – Brad Zacher Mar 11 '15 at 05:11
0

As far as I am aware there's no way to catch an exception but not catch inherited exceptions. The problem is that you're considering the base exception to be more specific than the inherited exception, which is the opposite of how they're intended to work (Inherited exceptions should be more specific subsets of their parent, so conceptually if you can handle the parent you should be able to handle the inherited exception).

Your options basically are:

  1. Create your own exception type & only catch this. If your exception falls under the definition of an InvalidOperationException then you can inherit from this. Then you can catch yours specifically.
  2. Catch, inspect, and re-throw if it's not what you're after. This technique I typically try to avoid but is sometimes required if exception types are too generic. e.g.

    catch (InvalidOperationException ex) { 
       if (ex.GetType() != typeof(InvalidOperationException)) throw;
       /* Do stuff */
    }
    
John Saunders
  • 160,644
  • 26
  • 247
  • 397
fyjham
  • 7,004
  • 2
  • 32
  • 40
0

It is not possible to only catch base exceptions.

In this case it is best to create a custom exception, rather than use the system's exception types.

public class HttpErrorException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }
    public HttpErrorException(HttpStatusCode code, string message)
        : base(message)
    {
        this.StatusCode = code;
    }
}

throw new HttpErrorException(400, "You sent a bad request!");

If the original intention was to obfuscate the HTTP status codes, and instead use their text names, factory methods can be created.

public class HttpErrorException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }

    private HttpErrorException(HttpStatusCode code, string message)
        : base(message)
    {
        this.StatusCode = code;
    }

    public static HttpErrorException BadRequest(string message)
    {
        return new HttpErrorException(400, message);
    }

    public static HttpErrorException InternalServerError(string message)
    {
        return new HttpErrorException(500, message);
    }
    // etc
}

throw HttpErrorException.BadRequest("You made a bad request!");
Brad Zacher
  • 2,915
  • 18
  • 31