title: How do I return json for 404s and 403s in WebAPI?
body: <p>I have a fairly simple web API application that currently has one route setup.  If the user attempts to access any other route they get a 404 back but the body of the 404 is HTML instead of JSON (which is what their accept header asks for).  What is the <em>easiest</em> (least code/config added to my project) way to get IIS to respond to requests of non-existant routes with a JSON error response rather than a webpage?</p>
  
  <p>The same question applies to 403s.  If I try to navigate to the root of my application I get a 403 back, once again as a webpage.  I would prefer this be a 404, but the bigger question is how do I make <em>all</em> responses from my application be JSON rather than only responses on valid routes?  I mention the 403 because I am looking for a broader solution than just setting up a catch-all route, since I don't believe that will help me with the 403 or any other random exception that occurs outside of a controller action.</p>
  
  <p>Preferrably, I would like my application to respect the accept header on the request.  However, since my API only supports JSON right now, I am willing to live with (for the time being) it always responding with JSON.</p>
  
  <p>I'm using WebAPI 2.2 and .NET 4.5.2.</p>
  
  <p><strong>Edit</strong></p>
  
  <p>This isn't a formatter issue.  The formatters are correctly applied to successful messages, respecting the accept header in the request.  This is specifically an issue with unhandled routes and web server errors (like forbidden when trying to access web root).</p>
  
  <p><strong>Edit 2</strong></p>
  
  <p><em>Steps to reproduce:</em></p>
  
  <ol>
  <li>Open Visual Studio 2013 Update 4</li>
  <li>New Project</li>
  <li>Choose .NET Framework 4.5.2</li>
  <li>Choose Templates > Visual C# > Web > ASP.NET Web Application</li>
  <li>Choose "Empty", leave all folders and core references <strong>unchecked</strong>.</li>
  <li>Right Click on the project > Add > New Scaffold Item > Web API 2 Controller - Empty</li>
  <li>Modify DefaultController as shown below.</li>
  <li>Modify WebApiConfig.cs as shown below.</li>
  <li>Run/Debug</li>
  </ol>
  
  <p>What I expect is that when I navigate to <code>http://localhost:&lt;port&gt;/api/do_stuff</code> I see <code>Success!</code> in either XML or JSON depending on accept headers (which I do) and when I navigate to any other page I should see <code>Failure!</code> (which I don't).  Instead when I navigate to any other page I see IIS's 404 response.</p>
  
  <p>DefaultController.cs: </p>
  
  <pre><code>[RoutePrefix("api")]
  public class DefaultController : ApiController
  {
      [HttpGet]
      [Route("do_stuff")]
      public String DoStuff()
      {
          return "Success!";
      }
  }
  </code></pre>
  
  <p>WebApiConfig.cs:</p>
  
  <pre><code>public static class WebApiConfig
  {
      public static void Register(HttpConfiguration config)
      {
          config.MapHttpAttributeRoutes();
          config.Filters.Add(new CustomExceptionFilter());
      }
  
      private class CustomExceptionFilter : ExceptionFilterAttribute
      {
          public override void OnException(HttpActionExecutedContext actionExecutedContext)
          {
              if (actionExecutedContext.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
              {
                  actionExecutedContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.NotFound)
                  {
                      Content = new StringContent(@"""Failure!"""),
                  };
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>Edit 3</strong></p>
  
  <p>I have also tried adding a global exception handler and exception logger as shown here:
  <a href="http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling" rel="noreferrer">http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling</a></p>
  
  <p>Neither are called when I try to navigate to an invalid route or navigate to site root in the above example.</p>