FormatterContext formatterContext, System.Net.TransportContext transportContext)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
But that always gives a 500 error: "System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details"
You will not be able to do this as its too late to send a "new" httpresponse while you are in midst of writing one. What is your scenario here? Could you validate your incoming request and send back a BadRequest response from different places like
MessageHandlers, Filters, Action etc?
This is also true for exceptions that occur while writing data to the stream. I mean let's say you are in middle of seralizing an Order object and after writing half data of this Order object onto the stream, if an exception occurrs, it will cause the connection
to be closed.
However, there seems to be a difference in the end behavior of what would happen when exceptions like these are thrown in case of Selfhost vs Webhost.
In SelfHost : exceptions thrown at OnWriteToStreamAsync, will result in closing of the connection
In WebHost: its the exception what you are noticing.
This difference in behavior could probably be a bug. We will investigate further regarding this.
This discussion reached the stage where MediaTypeFormatters looked like the best approach. I have cleared the default media formatters and added specific media formatters for types that I handle. If no media formatters are matched for the response, you then
get a "Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for
details." yellow screen of death (internally it says that Headers.ContentType cannot be null).
Therefore I added a CatchAllMediaTypeFormatter that I was hoping to mask any such server errors and assume that the request that came in didn't meet some criteria (therefore issue a 400 rather than 500 or worse 200). We will of course turn yellow screen
off for production and probably issue 404 for security, and hopefully none of our controllers would ever return something that failed to transform.
Perhaps this scenario is too convoluted and it's likely that not having a transform would/should be picked up by the developer (am working on a POC) but obviously would like to find out the level of control we have in each of the layers.
3. You mentioned about Headers.ContentType being Null...Doesn't your request have a ContentType header?...If yes, then we would
not know how to deserialize the request content due to insufficient information...
...this should not be happening because currently WebAPI will always use the first formatter in the Config.Formatters collection for the response media type even if it does
not have a matching media type formatter.
Thanks for the response so the post you refer to pretty much says use a DelegatingHandler to validate what you can upfront like checking there'll be a mediaTypeFormatter available to process the request.
This answers question 3 as well - I understand you wouldn't know what to do but I just wanted some customisation of what happened in this case :-) so checking there is either a valid content-type header or accept header with the appropriate body checks in
a delegating handler seems the way to go.
EDIT: I may have been too hasty marking this as answered. It is tricky to evaluate whether you'll have a valid mediaTypeFormatter to handle the request given they can opt-in based on the type the controller is receiving (which is very handy
for our transforms so please don't take it away :-)). In the delegatingHandler I don't know which controller method is being targeted so I cannot easily say if I'll have a mediaTypeFormatter available.
I had a quick look at the IFormatterSelector interface to see if I could replace the implementation of that but it doesn't look like I can do much about it even if I did replace it. For now we'll validate what we can upfront and deal with any 500s in the
Application_Error in global.asax.
LittleClive
Member
91 Points
65 Posts
How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 11:10 AM|LINK
I've tried:
FormatterContext formatterContext, System.Net.TransportContext transportContext) { throw new HttpResponseException(HttpStatusCode.BadRequest); }But that always gives a 500 error: "System.Web.Http.HttpResponseException: Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details"
I've also tried:
FormatterContext formatterContext, System.Net.TransportContext transportContext) { TaskCompletionSource source = new TaskCompletionSource();But this gives a 200 and a blank body.
Kiran Challa
Participant
1442 Points
281 Posts
Microsoft
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 12:58 PM|LINK
You will not be able to do this as its too late to send a "new" httpresponse while you are in midst of writing one. What is your scenario here? Could you validate your incoming request and send back a BadRequest response from different places like MessageHandlers, Filters, Action etc?
This is also true for exceptions that occur while writing data to the stream. I mean let's say you are in middle of seralizing an Order object and after writing half data of this Order object onto the stream, if an exception occurrs, it will cause the connection to be closed.
However, there seems to be a difference in the end behavior of what would happen when exceptions like these are thrown in case of Selfhost vs Webhost.
In SelfHost : exceptions thrown at OnWriteToStreamAsync, will result in closing of the connection
In WebHost: its the exception what you are noticing.
This difference in behavior could probably be a bug. We will investigate further regarding this.
Hope this helps...
Kiran Challa
LittleClive
Member
91 Points
65 Posts
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 01:57 PM|LINK
My scenario is related to http://forums.asp.net/t/1770906.aspx/1?How+do+I+add+a+custom+ModelBinder+ where I want to do transforms between representations of resources for different versions of the API.
This discussion reached the stage where MediaTypeFormatters looked like the best approach. I have cleared the default media formatters and added specific media formatters for types that I handle. If no media formatters are matched for the response, you then get a "Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details." yellow screen of death (internally it says that Headers.ContentType cannot be null).
Therefore I added a CatchAllMediaTypeFormatter that I was hoping to mask any such server errors and assume that the request that came in didn't meet some criteria (therefore issue a 400 rather than 500 or worse 200). We will of course turn yellow screen off for production and probably issue 404 for security, and hopefully none of our controllers would ever return something that failed to transform.
Perhaps this scenario is too convoluted and it's likely that not having a transform would/should be picked up by the developer (am working on a POC) but obviously would like to find out the level of control we have in each of the layers.
Kiran Challa
Participant
1442 Points
281 Posts
Microsoft
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 02:30 PM|LINK
OK, I haven't gone through the other thread that you have mentioned...but I have some comments:
1. So, you have cleared the default formatter collection and added your own formatters.
2. Are you seeing that if you now make a request with an un-supported media type, then you are seeing an exception?...this should not be happening because currently WebAPI will always use the first formatter in the Config.Formatters collection for the response media type even if it does not have a matching media type formatter. By the way, you can change this behavior if your do not want it as people discussed here:http://forums.asp.net/t/1770538.aspx/1?conneg+bug+Should+return+406+Not+Acceptable+instead+of+json+when+Accept+Header+is+present+and+media+type+not+supported
3. You mentioned about Headers.ContentType being Null...Doesn't your request have a ContentType header?...If yes, then we would not know how to deserialize the request content due to insufficient information...
Kiran Challa
FutureCode
Member
76 Points
20 Posts
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 05:36 PM|LINK
Shouldn't this be a 406 or 415 response?
Kiran Challa
Participant
1442 Points
281 Posts
Microsoft
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 24, 2012 05:45 PM|LINK
Regarding 406 , there was a discussion about this in the following thread:
http://forums.asp.net/t/1770538.aspx/1?conneg+bug+Should+return+406+Not+Acceptable+instead+of+json+when+Accept+Header+is+present+and+media+type+not+supported
Kiran Challa
LittleClive
Member
91 Points
65 Posts
Re: How do I return 400 BadRequest in a MediaTypeFormatter?
Feb 29, 2012 02:35 PM|LINK
Thanks for the response so the post you refer to pretty much says use a DelegatingHandler to validate what you can upfront like checking there'll be a mediaTypeFormatter available to process the request.
This answers question 3 as well - I understand you wouldn't know what to do but I just wanted some customisation of what happened in this case :-) so checking there is either a valid content-type header or accept header with the appropriate body checks in a delegating handler seems the way to go.
EDIT: I may have been too hasty marking this as answered. It is tricky to evaluate whether you'll have a valid mediaTypeFormatter to handle the request given they can opt-in based on the type the controller is receiving (which is very handy for our transforms so please don't take it away :-)). In the delegatingHandler I don't know which controller method is being targeted so I cannot easily say if I'll have a mediaTypeFormatter available.
I had a quick look at the IFormatterSelector interface to see if I could replace the implementation of that but it doesn't look like I can do much about it even if I did replace it. For now we'll validate what we can upfront and deal with any 500s in the Application_Error in global.asax.