60

I am developing a RESTful service and I want to return 400 for all unsupported URLs.

My question is when should I choose method 1 over method 2 and vice-versa..

//method 1
public ActionResult Index()
{
    //The url is unsupported
    throw new HttpException(400, "Bad Request");
}

This one seems to be better?

//method 2
public ActionResult Index()
{
    //The url is unsupported
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Bad Request");
}

5 Answers 5

51

The second seems better as it doesn't involve exception throwing which comes at a micro-cost compared to the first example.

Sign up to request clarification or add additional context in comments.

10 Comments

I'm sure there must be a more semantically meaningful difference between the two than simply the overhead of exception throwing.
@AntP, with the first you are hoping that ASP.NET MVC will intercept this HttpException and return the corresponding status code - a behavior that might change some day. With the second everything is very explicit. You are telling exactly what should happen in this case - return 400 BadRequest to the client.
No, it's exactly the contrary. The second is more robust. As I said with the first you are relying on the fact that some code will intercept the exception you threw, will analyze its type and since it is an HttpException it will extract the StatusCode you have set and return it to the client. With the second you are directly and explicitly sending this status code to the response. What more robust than that you want?
The second one is not caught by the exception filter. So in case you have a global exception filter, the second options would not record any exception.
I have already expressed my opinion on the matter. If you prefer, go ahead throwing. I won't use the first code. But I respect your opinion on the subject.
|
13

Being in a DevOps team, we are all in the mind-set where throwing more hardware at something to get a slightly better result is always a good cause. So I'm intentionally ignoring the micro-cost of firing a .NET exception.

If you're leveraging a telemetry framework like ApplicationInsights then just returning the status code gives you nothing more than a "failed request". It doesn't give you any useful information that allows you to either compile or get any information on the "why" of the failed request.

Telemetry platforms expect and want you to throw, because error telemetry is usually around .NET exceptions, so if you're not throwing you're creating a problem for operations.

I actually landed here, because I'm in the process of writing a Roslyn analyser and CodeFix for a project where folks love to write try{} catch { return BadRequest("put_the_reason_here"); } and neither DevOps or the Dev teams see nothing useful in the system telemetry in ApplicationInsights.

Comments

10

In my view you need to consider first if a request is made to the unsupported URLs. Then do you think of it is an exceptional situation or you expect that to happen? If you think of it as an exceptional situation then create and throw an exception (option 1). If you are expecting that you will receive many requests on the unsupported URL then treat it as a function of your application and use method 2.

That's said you will need to think about your clients' again if you are expecting too many requests on the unsupported URLs. In general I would prefer to throw an exception as I don't expect to receive too many requests on the unsupported URLs, and if it does happen then I would like to log it as an exception and investigate the reason.

Comments

1

Although this question is a bit old I figured I'd give my input since I came across this.

Errors are values. This goes for an HttpException (when unthrown) as well as an HttpStatusCodeResult. Thrown exceptions, however, create new code paths that are hidden away from your coworkers that may be one execution context higher up than yours and have to be given documentation that these code paths will be passed to them without notice. Values, however, tell you everything you need to know through their type. You can use their type in the expected execution path to tell whether an error has occured as well as find associated information with that error and log it.

I sometimes use (lightly extended) Exception's without throwing them to the next execution context to extract the useful debug information that David Rodriguez mentioned. There's never an excuse to be handing thrown exceptions to execution contexts above you that aren't actually exceptional, and this only really applies to things that are actually outside of your code's ability to handle (StackOverflowException, other fatal system exceptions, etc).

In a networked application, such as whatever MVC service you're running, the performance penalty from throwing exceptions is meaningless. The semantics and effects on maintainability, are not.

Network errors are values, and you should handle them like so.

3 Comments

Don't you consider an unsupported url as an exceptional situation in mvc?
An unsupported url is not an exceptional situation to me because I draw the line between exceptions and errors as the difference between things outside of my control at runtime (exceptions thrown from bad code and system failure such as out of memory), and things within my control in the runtime (poor user input). Inappropriate input is not an exceptional situation, but an erroneous situation, that should be handled with standard, visible code paths instead of hidden thrown code paths, as exception handling increases complexity and hidden code paths a large amount, and are expensive.
I agree with humanoidanalog -- in ASP.NET MVC, I consider most HTTP errors to be expected behavior. After all, the reason I'm putting in different codes for certain responses is because I'm anticipating the need to do so.
0

you would throw an exception in code locations that cannot return an actionResult, such as in a controller constructor.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.