Exceptions and StatusCode in ASP.NET Core MVC - asp.net-core

We have UseExceptionHandler (handle Exeptions) and UseStatusCodePages (handle StatusCode). Why in ASP.NET Core MVC we using StatusCodeResult than just handy extend Exception?

UseExceptionHandler is generally used to catch up unexpected errors and preset them in a more friendly manner to the user.
Whereas status codes are more important in REST API to signal the client the success or failure (and specific cause of the failure) of the specific operation.
Controller action should never throw exception and access a specific resource (i.e. db record) which doesn't exist you should return 404 (not found). When passed data is invalid rest apis return "400 bad request", on success 200. When new resource is created 201 (with "Location" header which contains the url to the new resource, see CreatedAtAction method of the controller class).
With views it works differently where you render the error directly into the HTML Code. You can also return status codes with MVC-esque view controllers and handle it with UseStatusCodePages (i.e. showing a generic NotFound.cshtml template for resources which don't exist).
Also your question sounds like you want to use exceptions to set status code, this is wrong for a couple of reasons.
Exceptions should be (as their name suggest) exceptional; Read: when something unexpected happens. For example if you try to withdraw a negative balance from your bank account and further processing it makes no sense or becomes impossible.
When you expect an error, you should return a result or handle it differently. For validations you should use Result classes (i.e. IdentityResult from ASP.NET Core Identity, which contains a Success property and a property which contains a list of error messages in case the operation or the validation fails).
Throwing and catching Exceptions is quite expensive, so they should really only be thrown when (as pointed above) something unexpected happens. Not finding a record is nothing unexpected.
(Ab)using exceptions for flow control (deciding which code path to execute) is just wrong. That's what if/switch and patterns like strategy pattern are for. Exceptions will just make the code unreadable and harder to maintain.

Related

Apikit - status code best practices

Using APIKit in Mule, I need to return a 404 status code if a particular resource is not found when executing my flow.
I can see three ways of handling this:
Throw a custom business exception(using a groovy script) i.e
PersonNotFoundException and use the
apikit:mapping-exception-strategy to map that exception to '404'
Throw the existing Mule exception
org.mule.module.apikit.exception.NotFoundException which is already
mapped to '404'
Do no throw an exception and manually set the http response and
status code within the normal flow of my message.
What's the best practice here? Use exceptions for flow control? and if so use the Mule exception or a custom business exception?
I think this is one of those weird combinations between API best practices and Mule best practices.
For generic resources, ie "/users" I would use the Mule Not Found Exception (404), but for an item resource that does not exist, ie "/users/jim-smith" for usability purposes I would throw a custom exception with "The user requested does not exist" or "You do not have permission to access this user" (status 401) whichever the case may be to best help developers utilizing your API.
I think the biggest advantage to the exception strategy instead of just manually changing the responses yourself is it creates a clear flow where you can easily determine what is a successful response, and what is a failed response.
That and using an exception handler within Mule you can return back a uniform error response to the user (in JSON, XML, etc).
But others might disagree with me, and just manually setting the status code and response yourself does offer the most flexibility, but also allows for inconsistencies.

Error vs Meteor.Error

What is the difference between throw new Error and using Meteor.Error()? Is it simply that throw new Error will not be shown to the client, only on the server (the client will get a 500 Internal server error); and Meteor.Error will be sent to the client.
Are there any more differences? E.g. Does one break out of Fibers, stops downstream code?
The main thing with Meteor.Error is like you mentioned
A full stack trace (may not be given by Error always)
Possibility to send the error down to the client, in a limited non revealing form.
Hide the error from the server in certain cases (if its thrown in a method or publish method, and from hooks such as Accounts.onLoginAttempt)
The objects inside are EJSON serialised so a variety of data can be sent down to the client
When a Meteor.Error is thrown, because of the EJSON serialisation you get a bit more information on the server side.
Meteor displays the errors better.
Often you can get [Object object] as the reason to be displayed from ordinary errors when they come from ordinary Errors, from Meteor.wrapAsync
Theres not much else that's different, Meteor.Error is a a subclass of Error with the above changes.
So they'll both stop downstream code. When it comes to Fibers, if the ordinary one is thrown out of a Fiber in any way its likely to stop your app (on the server side & not in a method, startup, Meteor.setInterval, publish, etc)
Its definition is also quite small: https://github.com/meteor/meteor/blob/devel/packages/meteor/errors.js

The use of HTTP status to communicate application circumstances

Suppose I ask a question to an criminal register: http://server/demographics/party/{partyId} and that person is not known on that system.
Is that an error? Isn't it a good thing?
When returning 404, it is an error code, Restlet has implemented it as a specific URL cannot be resolved to a route to a server-resource (a handling class), an erroneous situation.
In my opinion, if a system understands a call, and is able to process it without errors, it should return 200 (HTTP-ok), and it should return the information: "We don't know this person".
What is the best thing to do?
There's nothing wrong in returning a 404 status code. It simply means "you asked for a resource, and it doesn't exist". If it did return 200, it would have to somehow return an additional status code telling you that everything went fine, but the resource couldn't be found. That's unnecessary, because 404 already means exactly that.
A status 500 is normally returned to mean "something went wrong, I can't tell you if the resource exists or not". Now if you returned a 404 to mean that, this would be a mistake.
Whether it's a good thing or not is not doesn't have anything to do with HTTP or REST. And BTW, if the register was a file containing the survivors of a disaster, you would probably find it bad to not find the person you looked for, unless maybe if the person is your mother in law, unless you actually love your mother in law. (this is meant as a joke, for those who don't find it obvious).
A web service could be implemented in a way that produces either kind of response.
If it is being implemented in a way that is truer to HTTP/Rest, then '404 not found' would be the appropriate response for not finding something. This is what the 404 status is for.
It may help to think of your request as saying 'I assume this record exists, and I want to see it', and the 404 response as saying 'You are in error that record does not exist'.
If this URL is going to be used by code (rather than be displayed in a browser), then if you don't make a distinction in the response status then you will have to add extra information to the response body to make the difference obvious.
If this URL is going to be displayed to a user in a browser, then the server is still able to display content in the response body for a 404.
Please read: http://archive.oreilly.com/pub/post/restful_error_handling.html#__federated=1
Quoting:
Conclusion:
Human Readable Error Messages: Part of the major appeal of REST based web services is that you can open any browser, type in the right URL, and see an immediate response -- no special tools needed. However, HTTP error codes do not always provide enough information. For example, if we take option 1 above, and request and invalid book ID, we get back a 404 Error Code. From the developer perspective, have we actually typed in the wrong host name, or an invalid book ID? It's not immediately clear. In Option 3 (DAS), we get back a blank page with no information. To view the actual error code, you need to run a network sniffer, or point your browser through a proxy. For all these reasons, I think Option 4 has a lot to offer. It significantly lowers the barrier for new developers, and enables all information related to a web service to be directly viewable within a web browser.
Application Specific Errors: Option 1 has the disadvantage of not being directly viewable within a browser. It also has the additional disadvantage of mapping all HTTP error codes to application specific error codes. HTTP status codes are specific to document retrieval and posting, and these may not map directly to your application domain. For example, one of the DAS error codes relates to invalid genomic coordinates (sequence coordinate is out of bounds/invalid). What HTTP error code would we map to in this case?
Machine Readable Error Codes: As a third criteria, error codes should be easily readable by other applications. For example, the XooMLe application returns back only human readable error messages, e.g. "Invalid Google API key supplied". An application parsing a XooMLe response would have to search for this specific error message, and this can be notoriously brittle -- for example, the XooMLe server might simply change the message to "Invalid Key Supplied". Error codes, such as those provided by DAS are important for programmatic control, and easy creation of exceptions. For example, if XooMLe returned a 1001 error code, a client application could do a quick lookup and immediately throw an InvalidKeyException.
Based on these three criteria, here's my vote for best error handling option:
Use HTTP Status Codes for problems specifically related to HTTP, and not specifically related to your web service.
When an error occurs, always return an XML document detailing the error.
Make sure the XML error document contains both an error code, and a human readable error message. For example:
1001
Invalid Google API key supplied
By following these three simple practices, you can make it significantly easier for others to interface with your service, and react when things go wrong. New developers can easily see valid and invalid requests via a simple web browser, and programs can easily (and more robustly) extract error codes and act appropriately.
The Amazon.com web services API follows the approach of returned XML document can specify an ErrorMsg element.
XooMLe also follows this approach. (XooMLe provides a RESTful API wrapper to the existing SOAP based Google API).
Another approach is by DAS ( Distributed Annotation System) which always returns 200 if there was no HTTP-error and has error information in the HTTP-header, which is less favorable, because it is not human readable, as a browser does not display the HTTP-header.

Handling Errors From HTTPWebRequest/HTTPWebResponse

I have a class called Hotmail that contains various method such as login, logout etc.
To illustrate the confusion I'm having I have a login method that logs the user into Hotmail via my software. The login method returns a HttpWebResponse object. But, within the login method any number of things could happen such as wrong credentials being entered or a timeout.
I'm in some confusion about how, and where to handle such errors.
In the case of the wrong credentials being entered, or a timeout, it would be pointless, or sometimes not possible to return a HttpWebResponse object. What would be the best way to handle such errors?
Should I create custom Exceptions so the code that's calling the method can check for such errors and handle them?
What's the conventional way to handle these sorts of errors as I'm sure this is a common point of confusion?
Assuming that you have something like Hotmail>>login(user, password) I would definitely use exceptions. How fine grained to be with exceptions its up to you (and your domain model) and it can be hard to achieve a balance.
For this case I would definitely have exceptions for the most important events (like WrongCredentialsException) but I wouldn't have an exception class for every 4XX and 5XX response errors. However, according to your domain and personal tastes you could have a ClientException and ServerException, with an instance variable stating the error number instead of just having a ConnectionException.
HTH

To fault or not to fault

I'm having a discussion with a colleague about when to throw faults and when not to throw faults in a WCF service.
One opinion is, that we only throw faults when the service operation could not do its work due to some error; and something may be in an invalid state because of it. So, some examples:
ValidateMember(string name, string password, string country)
-> would throw a fault if the mandatory parameters are not passed, because the validation itself could not be executed;
-> would throw fault if some internal error occured, like database was down
-> would return a status contract in all other cases, that specifies the result of the validation (MemberValidated, WrongPassword, MemberNotKnown,...)
GetMember(int memberId)
-> would only throw fault if something is down, in all other cases it would return the member or null if not found
The other opinion is that we should also throw faults when GetMember does not find the member, or in the case of ValidateMember the password is wrong.
What do you think?
My take on this...
There are three causes of failure:
The service code threw an exception, e.g. database error, logic error in your code. This is your fault.
The client code failed to use your service properly according to your documentation, e.g. it didn't set a required flag value, it failed to pass in an ID. This is the client software developer's fault.
The end user typed in something silly on screen, e.g. missing date of birth, negative salary. This is the end user's fault.
It's up to you how you choose to map actual fault contracts to each cause of failure. For example, we do this:
For causes 1 and 2, all the client code needs to know is that the service failed. We define a very simple "fatal error" fault contract that contains only a unique error ID. The full details of the error are logged on the server.
For cause 3, the end user needs to know exactly what he/she did wrong. We define a "validation errors" fault contract containing a collection of friendly error messages for the client code to display on screen.
We borrow the Microsoft EntLib class for cause 3, and use exception shielding to handle causes 1 and 2 declaratively. It makes for very simple code.
To Clarify:
We handle the three causes like this inside the service:
An unexpected exception is thrown in the service code. We catch it at the top level (actually exception shielding catches it, but the principle is the same). Log full details, then throw a FaultException<ServiceFault> to the client containing only the error ID.
We validate the input data and deliberately throw an exception. It's normally an ArgumentException, but any appropriate type would do. Once it is thrown, it is dealt with in exactly the same way as (1) because we want to make it appear the same to the client.
We validate the input data and deliberately throw an exception. This time, it's a FaultException<ValidationFault>. We configure exception shielding to pass this one through un-wrapped, so it appears on the client as FaultException<ValidationFault> not FaultException<ServiceFault>.
End result:
No catch blocks at all inside the service (nice clean code).
Client only has to catch FaultException<ValidationFault> if it wants to display messages to the user. All other exception types including FaultException<ServiceFault> are dealt with by the client's global error handler as fatal errors, since a fatal error in the service generally means a fatal error in the client as well.
It it is a common, routine failure, then throwing a fault is a mistake. The software should be written to handle routine items, like entering the wrong password. Fault processing is for exceptional failure which are not considered part of the program's normal design.
For example, if your program was written with the idea that it always has access to a database, and the database is not accessible, that's an issue where the "fix" is well outside of the limits of your software. A fault should be thrown.
Fault processing uses different logical flows through the structure of the programming language, and by using it only when you've "left" the normal processing of the programming problem, you will make your solution leverage the feature of the programming language in a way that seems more natural.
I believe it is good practice to separate error handling and fault handling. Any error case should be dealt by your program - fault handling is reserved for exceptional conditions. As a guide to the separation of the two I found it useful when considering such cases to remember that there are only three types of error (when handling data and messages) and only one type of fault.
The error types are related to different types of validation:
Message validation - you can determine from the message contents that the data is valid or invalid.
Example: content that is intended to be a date of birth - you can tell from the data whether it is valid or not.
Context validation - you can only determine that content is invalid by reference to the message
combined with the system state.
Example: a valid date of joining a company is earlier than that persons date of birth.
Lies to the system - you can only determine that a message was in error when a later message
throws up an anomaly.
Example: Valid date of birth stored and inspection of the person's birth certificate shows this to be incorrect. Correction of lies to the system generally require action outside of the system, for instance invoking legal or disciplinary remedies.
Your system MUST deal with all classes of error - though in case three this may be limited to issuing an alert.
Faults (exceptions) by contrast only have one cause - data corruption (which includes data truncation). Example: validation parameters are not passed.
Here the appropriate mechanism is fault or exception handling - basically handing off the problem to some other part of the system that is capable of dealing with it (which is why there should be an ultimate destination for unhandled faults).
In the old days we used to have a rule that exceptions were only for exceptional and unexpected things. One of the reasons you did not want to use them too much was that they "cost" alot of computing power.
But if you use exceptions you can reduce the amount of code, no need for alot of if else statements, just let the exception bubble up.
It depends on your project. The most important thing is that there is a project standard and everyone does it the same way.
My opinion is that exceptions/fault should be thrown whenever what the method is supposed to do can't be achieved. So validation logic should never raise exception except if the validation can't be made (i.e. for technical reasons) but never just because the data are not valid (in that case it will return validation codes/messages or anything helping the caller to correct the data).
Now the GetMember case is an interesting one because it's all about semantic. The name of the method suggest that a member can be retrieved by passing an id (compare to a TryGetMember method for exemple). Of course the method should not throw the same exception if the id is nowhere to be found or if the database does not respond but a wrong id passed to this method is probably the sign that something is going wrong somewhere before that call. Except if the user can directly enter a member-id from within the interface in which case a validation should occurred before calling the method.
I hear a lot about the performance issue. I just made a simple test using C# and trow/catch 1000 exceptions. The time it took is 23ms for 1K Exeptions. That's 23ยต per exception. I think performance is no longer the first argument here except if you plan to raise more than 2000 exception per second in which case you will have a 5% performance down, which I can start considering.
My humble opinion...