My beautiful REST webservice works great. Except if I visit pages like ~/, which returns the default IIS 403 Forbidden page (even using Fiddler and specifying only Accept: application/json). I want nothing but JSON or XML errors. Is there a way to override ALL exceptions with a custom exception handler? or a default controller to handle all unknown requests? What’s the simplest, and the most correct (if different), way to handle this so that clients need only parse REST API-friendly XML datagrams or JSON blobs?
Example Request:
GET http://localhost:7414/ HTTP/1.1
User-Agent: Fiddler
Host: localhost:7414
Accept: application/json, text/json, text/xml
Response: (that I don’t like, notice that text/html wasn’t one of the accepted response types)
HTTP/1.1 403 Forbidden
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?QzpcaWNhcm9sXENoYXJpdHlMb2dpYy5pQ2Fyb2wuQXBp?=
X-Powered-By: ASP.NET
Date: Fri, 25 Jan 2013 21:06:21 GMT
Content-Length: 5396
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IIS 8.0 Detailed Error - 403.14 - Forbidden</title>
<style type="text/css">
<!--
...
Response (that I would prefer):
HTTP/1.1 403 Forbidden
Cache-Control: private
Content-Type: application/json; charset=utf-8
Date: ...
Content-Length: ....
{
"error":"forbidden",
"status":403,
"error_description":"Directory listing not allowed."
}
Edit 1/26/14: Microsoft just added “Global Error Handling” to the latest WebAPI 2.1 update.
Ok, I think I’ve got it. There’s a few parts to it.
First: Create a controller for your errors. I named my actions according to the HTTP error codes.
Next, I created a
GenericExceptionFilterAttributethat checks to see if the HttpActionExecutedContext.Exception is populated and if the response is still empty. If both cases are true, then it generates a response.In my case, I went with a single generic handler that I could register support for each of the main exception types and map each of those exception types to specific HTTP response codes. Now register your exception types and handlers this filter globally in your
global.asax.cs:Next, create a catchall route to send all unknown requests to your new Error handler:
And, to wrap it all up, let IIS process all requests through ASP.NET by adding this to your
web.config:Optionally, you could also use the
customErrorssection of theweb.configto redirect all errors to your new error handler.