There is an ExceptionFilterAttribute to handle exceptions thrown inside actions. But i need to intercept exceptions thrown before invoking any actions (parsing request body/params) to provide meaningful error responses to users. Is there any way do this?
If there is an unhandled exception outside of MVC then the global.asax
Application_Error is an event you can hook into to be notified. Inside you can access the Context.Error property for the exception that was thrown.
void Application_Error()
{
var ex = Context.Error;
}
You can always then call Response.Redirect or Server.Transfer in here if needed. Also, there's the built-in
<customErrors> element in web,config that configures default error pages based upon errors.
But i need to intercept exceptions thrown before invoking any actions (parsing request body/params)
Do you mean you want to handle exceptions thrown at the Model Binding stage? Actually exceptions thrown at this stage should be caught at the exception filters. Are you seeing something different?
Just FYI...exceptions (except of typeHttpResponseException) thrown at Authorization filters, Model Binding, Action Filters & Actions should be caught at Exception filters.
What part doesn't work? Do you mean Server.Transfer? Server.Transfer works at the web server level, but has never worked if you want to transfer to a routing URL (given how routing does its thing). So if that's what you're looking for, then you can always
do a redirect.
I guess it might help to learn a little more about what you're trying to do.
Exceptions thrown outside controller actions dont get intercepted by ExceptionFilter. Here is the response i get:
{
"ExceptionType":"System.InvalidOperationException","Message":"No 'MediaTypeFormatter' is available to read an object of type 'Mark' with the media type 'text/plain'.", "StackTrace":" at System.Net.Http.ObjectContent.SelectAndValidateReadFormatter(Boolean acceptNullFormatter) at System.Net.Http.ObjectContent.ReadAsyncInternal[T](Boolean allowDefaultIfNoFormatter) at System.Web.Http.ModelBinding.RequestContentReader.ReadWholeBodyAsync(HttpActionContext actionContext, Type modelType) at System.Web.Http.ModelBinding.RequestContentReader.ReadContentAsync(HttpActionContext actionContext) at System.Web.Http.ModelBinding.DefaultActionValueBinder.BindValuesAsync(HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.ApiController.<>c__DisplayClass3.<ExecuteAsync>b__0() at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)", "InnerException":null }
Yea, this is tricky -- looks like this exception is from the WebAPI content negotation layer when there's not matching media type formatter for the submitted data (during model binding). If the real problem is that there is no media type formatter to deal
with the submitted resource format then the response should be a
415 Unsupported Media Type. Henrik
just posted on some of the changed plumbing around this area -- his comment is about responses but maybe it relates to submitting data as well.
The other thing I notice is that you're sending text/plain as the Content Type... perhaps this isn't correct (or are you just doing testing of error conditions)? What format are you submiiting the data in?
The other thing I notice is that you're sending text/plain as the Content Type... perhaps this isn't correct (or are you just doing testing of error conditions)? What format are you submiiting the data in?
I send text/plain content type just to get an exception prior to invoking any actions (I'm sure there are other ways to get exceptions at this stage).
My solution is to subclass ApiController and provide exception handling code there. I dont know if it covers all cases, but works for the exception i had:
Exceptions thrown outside controller actions dont get intercepted by ExceptionFilter. Here is the response i get:
{
"ExceptionType":"System.InvalidOperationException","Message":"No 'MediaTypeFormatter' is available to read an object of type 'Mark' with the media type 'text/plain'.", "StackTrace":" at System.Net.Http.ObjectContent.SelectAndValidateReadFormatter(Boolean acceptNullFormatter) at System.Net.Http.ObjectContent.ReadAsyncInternal[T](Boolean allowDefaultIfNoFormatter) at System.Web.Http.ModelBinding.RequestContentReader.ReadWholeBodyAsync(HttpActionContext actionContext, Type modelType) at System.Web.Http.ModelBinding.RequestContentReader.ReadContentAsync(HttpActionContext actionContext) at System.Web.Http.ModelBinding.DefaultActionValueBinder.BindValuesAsync(HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.ApiController.<>c__DisplayClass3.<ExecuteAsync>b__0() at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)", "InnerException":null }
(i use mvc4 beta)
For this particular case I've added a special MediaTypeHandler at the end of the list that has CanRead/CanWrite returning true and throws an exception in the OnWriteToStreamAsync. This is then caught in Application_Error and it does a Server.Transfer to
a special controller that issues a response.
idmitriev
Member
10 Points
13 Posts
Handling exceptions thrown outside controller actions
May 14, 2012 01:47 PM|LINK
There is an ExceptionFilterAttribute to handle exceptions thrown inside actions. But i need to intercept exceptions thrown before invoking any actions (parsing request body/params) to provide meaningful error responses to users. Is there any way do this?
BrockAllen
All-Star
27432 Points
4890 Posts
MVP
Re: Handling exceptions thrown outside controller actions
May 14, 2012 02:14 PM|LINK
If there is an unhandled exception outside of MVC then the global.asax Application_Error is an event you can hook into to be notified. Inside you can access the Context.Error property for the exception that was thrown.
void Application_Error() { var ex = Context.Error; }You can always then call Response.Redirect or Server.Transfer in here if needed. Also, there's the built-in <customErrors> element in web,config that configures default error pages based upon errors.
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
idmitriev
Member
10 Points
13 Posts
Re: Handling exceptions thrown outside controller actions
May 14, 2012 05:03 PM|LINK
This doesnt really work with webapi as described here: http://stackoverflow.com/a/10298916/1393633
Kiran Challa
Participant
1442 Points
281 Posts
Microsoft
Re: Handling exceptions thrown outside controller actions
May 14, 2012 05:08 PM|LINK
Do you mean you want to handle exceptions thrown at the Model Binding stage? Actually exceptions thrown at this stage should be caught at the exception filters. Are you seeing something different?
Just FYI...exceptions (except of typeHttpResponseException) thrown at Authorization filters, Model Binding, Action Filters & Actions should be caught at Exception filters.
Kiran Challa
BrockAllen
All-Star
27432 Points
4890 Posts
MVP
Re: Handling exceptions thrown outside controller actions
May 14, 2012 05:26 PM|LINK
What part doesn't work? Do you mean Server.Transfer? Server.Transfer works at the web server level, but has never worked if you want to transfer to a routing URL (given how routing does its thing). So if that's what you're looking for, then you can always do a redirect.
I guess it might help to learn a little more about what you're trying to do.
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
idmitriev
Member
10 Points
13 Posts
Re: Handling exceptions thrown outside controller actions
May 14, 2012 05:35 PM|LINK
Exceptions thrown outside controller actions dont get intercepted by ExceptionFilter. Here is the response i get:
{
(i use mvc4 beta)
idmitriev
Member
10 Points
13 Posts
Re: Handling exceptions thrown outside controller actions
May 14, 2012 06:08 PM|LINK
I dont want to do a redirect, just provide a meaningful error message in the response.
BrockAllen
All-Star
27432 Points
4890 Posts
MVP
Re: Handling exceptions thrown outside controller actions
May 14, 2012 06:17 PM|LINK
Yea, this is tricky -- looks like this exception is from the WebAPI content negotation layer when there's not matching media type formatter for the submitted data (during model binding). If the real problem is that there is no media type formatter to deal with the submitted resource format then the response should be a 415 Unsupported Media Type. Henrik just posted on some of the changed plumbing around this area -- his comment is about responses but maybe it relates to submitting data as well.
The other thing I notice is that you're sending text/plain as the Content Type... perhaps this isn't correct (or are you just doing testing of error conditions)? What format are you submiiting the data in?
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
idmitriev
Member
10 Points
13 Posts
Re: Handling exceptions thrown outside controller actions
May 14, 2012 06:32 PM|LINK
I send text/plain content type just to get an exception prior to invoking any actions (I'm sure there are other ways to get exceptions at this stage).
My solution is to subclass ApiController and provide exception handling code there. I dont know if it covers all cases, but works for the exception i had:
Update: the code above does not intercept exceptions thrown when extracting action parameters from request :(
LittleClive
Member
91 Points
65 Posts
Re: Handling exceptions thrown outside controller actions
May 15, 2012 08:37 AM|LINK
For this particular case I've added a special MediaTypeHandler at the end of the list that has CanRead/CanWrite returning true and throws an exception in the OnWriteToStreamAsync. This is then caught in Application_Error and it does a Server.Transfer to a special controller that issues a response.