ASP.NET Web Api HttpResponseException 400 (Bad Request) Hijacked by IIS
Asked Answered
L

6

22

I'm writing a Web API service and trying to return a (400) Bad Request if my ModelState is invalid. I do not want a response body to be attached to this. It appears that IIS is hijacking my response and always returning a text/html content type with a lengthy, styled error page. This is a problem.

    [HttpPost]
    public void Link(LinkDeviceModel model)
    {

        if (ModelState.IsValid)
        {
            try
            {
                model.Save();
            }
            catch (Exception ex)
            {
                ErrorSignal.FromCurrentContext().Raise(ex);
                throw new HttpResponseException(ex.Message, HttpStatusCode.InternalServerError);
            }
        }
        else
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    }

Here is my fiddler request:

POST http://localhost/myapp/service/link HTTP/1.1
Host: localhost
Content-Length: 112
Content-Type: application/json
Accept: application/json

{"DeviceUniqueId":"CC9C6FC0-7D06-11E1-8B0E-31564824019B", "UserName": "[email protected]"," Pin": "111111"}

And my response erroneous, full of body, response:

    <!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 7.5 Detailed Error - 400.0 - Bad Request</title> 
<style type="text/css"> 
<!-- 
body{margin:0;font-size:.7em;font-family:Verdana,Arial,Helvetica,sans-serif;background:#CBE1EF;} 
code{margin:0;color:#006600;font-size:1.1em;font-weight:bold;} 
.config_source code{font-size:.8em;color:#000000;} 
pre{margin:0;font-size:1.4em;word-wrap:break-word;} 
ul,ol{margin:10px 0 10px 40px;} 
ul.first,ol.first{margin-top:5px;} 
fieldset{padding:0 15px 10px 15px;} 
.summary-container fieldset{padding-bottom:5px;margin-top:4px;} 
legend.no-expand-all{padding:2px 15px 4px 10px;margin:0 0 0 -12px;} 
legend{color:#333333;padding:4px 15px 4px 10px;margin:4px 0 8px -12px;_margin-top:0px; 
 border-top:1px solid #EDEDED;border-left:1px solid #EDEDED;border-right:1px solid #969696; 
 border-bottom:1px solid #969696;background:#E7ECF0;font-weight:bold;font-size:1em;} 
a:link,a:visited{color:#007EFF;font-weight:bold;} 
a:hover{text-decoration:none;} 
h1{font-size:2.4em;margin:0;color:#FFF;} 
h2{font-size:1.7em;margin:0;color:#CC0000;} 
h3{font-size:1.4em;margin:10px 0 0 0;color:#CC0000;} 
h4{font-size:1.2em;margin:10px 0 5px 0; 
}#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS",Verdana,sans-serif; 
 color:#FFF;background-color:#5C87B2; 
}#content{margin:0 0 0 2%;position:relative;} 
.summary-container,.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;} 
.config_source{background:#fff5c4;} 
.content-container p{margin:0 0 10px 0; 
}#details-left{width:35%;float:left;margin-right:2%; 
}#details-right{width:63%;float:left;overflow:hidden; 
}#server_version{width:96%;_height:1px;min-height:1px;margin:0 0 5px 0;padding:11px 2% 8px 2%;color:#FFFFFF; 
 background-color:#5A7FA5;border-bottom:1px solid #C1CFDD;border-top:1px solid #4A6C8E;font-weight:normal; 
 font-size:1em;color:#FFF;text-align:right; 
}#server_version p{margin:5px 0;} 
table{margin:4px 0 4px 0;width:100%;border:none;} 
td,th{vertical-align:top;padding:3px 0;text-align:left;font-weight:bold;border:none;} 
th{width:30%;text-align:right;padding-right:2%;font-weight:normal;} 
thead th{background-color:#ebebeb;width:25%; 
}#details-right th{width:20%;} 
table tr.alt td,table tr.alt th{background-color:#ebebeb;} 
.highlight-code{color:#CC0000;font-weight:bold;font-style:italic;} 
.clear{clear:both;} 
.preferred{padding:0 5px 2px 5px;font-weight:normal;background:#006633;color:#FFF;font-size:.8em;} 
--> 
</style> 

</head> 
<body> 
<div id="header"><h1>Server Error in Application "DEFAULT WEB SITE/MYAPP"</h1></div> 
<div id="server_version"><p>Internet Information Services 7.5</p></div> 
<div id="content"> 
<div class="content-container"> 
 <fieldset><legend>Error Summary</legend> 
  <h2>HTTP Error 400.0 - Bad Request</h2> 
  <h3>Bad Request</h3> 
 </fieldset> 
</div> 
<div class="content-container"> 
 <fieldset><legend>Detailed Error Information</legend> 
  <div id="details-left"> 
   <table border="0" cellpadding="0" cellspacing="0"> 
    <tr class="alt"><th>Module</th><td>ManagedPipelineHandler</td></tr> 
    <tr><th>Notification</th><td>ExecuteRequestHandler</td></tr> 
    <tr class="alt"><th>Handler</th><td>System.Web.Http.WebHost.HttpControllerHandler</td></tr> 
    <tr><th>Error Code</th><td>0x00000000</td></tr> 

   </table> 
  </div> 
  <div id="details-right"> 
   <table border="0" cellpadding="0" cellspacing="0"> 
    <tr class="alt"><th>Requested URL</th><td>http://localhost:80/myapp/service/link</td></tr> 
    <tr><th>Physical Path</th><td>C:\workspace\myapp\service\link</td></tr> 
    <tr class="alt"><th>Logon Method</th><td>Anonymous</td></tr> 
    <tr><th>Logon User</th><td>Anonymous</td></tr> 

   </table> 
   <div class="clear"></div> 
  </div> 
 </fieldset> 
</div> 
<div class="content-container"> 
 <fieldset><legend>Most likely causes:</legend> 
  <ul>  <li></li> </ul> 
 </fieldset> 
</div> 
<div class="content-container"> 
 <fieldset><legend>Things you can try:</legend> 
  <ul>  <li>Create a tracing rule to track failed requests for this HTTP status code. For more information about creating a tracing rule for failed requests, click <a href="http://go.microsoft.com/fwlink/?LinkID=66439">here</a>. </li> </ul> 
 </fieldset> 
</div> 


<div class="content-container"> 
 <fieldset><legend>Links and More Information</legend> 
  The request could not be understood by the server due to malformed syntax. 
  <p><a href="http://go.microsoft.com/fwlink/?LinkID=62293&amp;IIS70Error=400,0,0x00000000,7601">View more information &raquo;</a></p> 
  <p>Microsoft Knowledge Base Articles:</p> 
 <ul><li></li></ul> 

 </fieldset> 
</div> 
</div> 
</body> 
</html> 

I have tried to set TrySkipIisCustomErrors = True with great hope, but no luck. Any ideas? Appreciated. Thanks.

Levey answered 2/4, 2012 at 23:44 Comment(0)
S
35

Try adding this to your web.config. I had a very similar problem which this solved.

<configuration>
  <system.webServer>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>
</configuration>
Sweatband answered 3/4, 2012 at 20:0 Comment(7)
You rock. My Web Api is in a separate "Service" area. I added a web config vile to an empty "Views" folder in that area with the config above and that fixed it. Thanks.Levey
Great! Works great and TrySkipIisCustom wasn't working for me in Asp.NET MVC 4 Web Apis.Incubator
I'd +1 this answer, but it fails to explain what it does. Could you edit it to add an explanation please?Heathcote
I don't know what WebAPI does under the hood, I just know that it lets the error through from my own code and doesn't wrap it up in anything else. Sorry!Sweatband
This seems to have (some) explanation here: iis.net/configreference/system.webserver/httperrorsWhig
I spent hours trying to figure out why I was getting just "Bad Response" when the password was wrong. With this, I still get the 400 but now with a JSON containing the error_description. Thanks man!Urrutia
In WEB APi,Can i handle the error if my url is like this localhost:37500/<.Currently,it is returning 400 Error .Can anyone tell me how to handle thisFuddyduddy
T
4

Usually in such cases it is enough to set TrySkipIisCustomErrors = true on response object, but in case of Web API it sometimes doesn't do the trick (Web API even tries to set this flag internally by itself). For situations like this you can consider changing the IIS configuration. Please take a look here (you should be mostly interested in existingResponse="PassThrough").

Taxi answered 3/4, 2012 at 6:30 Comment(1)
TrySkipIisCustomErrors doesn't appear to be a member of WebApi's HttpResponseMessage however.Volt
O
3

Assuming you're inside of your APIController and don't need an ExceptionFilterAttribute to do any additional work for the response, then just return a response with the error status code instead of throwing an HttpResponseException.

return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid model.");
Osmious answered 18/3, 2014 at 18:17 Comment(1)
One thing I did notice is that I have to specify the second parameter (the content) or IIS would still display the custom error page instead.Osmious
U
3

I had the same problem with Asp.Net Webform application. The client sends ajax call to the server web handler (*.ashx).

I wanted to get the exception message back to the user. The Web handler sends back just the exception message and http status code 400.

The Trick is in Response.TrySkipIisCustomErrors = true;

try
{
//do some coding
}
catch (Exception exception)
{
    Log.Error(exception);
    context.Server.ClearError();
    context.Response.TrySkipIisCustomErrors = true;
    context.Response.ContentType = "text/plain";
    context.Response.Write(exception.Message);
    context.Response.StatusCode = 400;
    //400 Bad Request
    //The server cannot or will not process the request due to an apparent client error
    //
    //intentionally hidden exception 
    //prevent to send yellow page of death in ajax response
}
Unharness answered 15/8, 2016 at 15:25 Comment(0)
H
1

I was hitting this same condition, returning:

httpResponseMessage = context.Request.CreateResponse(statusCode);

Adding <httpErrors existingResponse="PassThrough"> didn't fix it, Content-type and the content body were missing in the response.

What did fix it was to construct the HttpResponseMessage like this:

var httpResponseMessage = context.Request.CreateResponse(statusCode, reasonPhrase);

By including the 'value' parameter (in this case, 'reasonPhrase') the Content-type and Content Body were present in the response.

Hendecagon answered 24/5, 2016 at 18:2 Comment(0)
B
0

I had a situation where I was calling a WebApi endpoint from another, and having read that HttpClients should be static I made that change. Worked fine for a few dozen messages but then would get intercepted by the self-host instance which would return a 400 Bad Request. There didn't seem to be anything wrong, especially with the initial success, but my original code would add a default header to the client prior to the call. After I made the client static this would have meant that I was adding the header multiple times to the same client. I changed the code to send create and send an HttpRequestMessage instead of letting the client do it, and added the header to the request. Seems to have solved my problem.

Benoni answered 18/8, 2017 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.