From here: http://stackoverflow.com/questions/15065594/error-handling-in-web-api-self-hosted-server-for-actionfilterattribute
As user mentions, when throwing HttpResponseException at the controller's action, exception filter is not executed...but throwing at an action filter is causing the exception filter to be executed.
I was able to repro this issue.
Following is repro code:
```
using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.SelfHost;
namespace Service
{
class Service
{
private static HttpSelfHostServer server = null;
private static AppSettingsReader appSettingsReader = null;
static void Main(string[] args)
{
appSettingsReader = new AppSettingsReader();
string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName);
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
try
{
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Service listenting at: {0} ...", baseAddress);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Exception Details:\n{0}", ex.ToString());
}
finally
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
}
public class SampleController : ApiController
{
[TestActionFilter]
[TestExceptionFilter]
public string Get()
{
//throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, "bad data"));
return "Hello";
}
public string Post([FromBody] string input)
{
return input;
}
}
public class TestActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
throw new HttpResponseException(actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, "bad data"));
}
}
public class TestExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
Console.WriteLine("Exception type" + actionExecutedContext.Exception.GetType().ToString());
}
}
}
```
Comments: This was an intentional implementation. The HttpResponseException is a way to short-circuit the request processing pipeline and return a HttpResponseMessage. There are a number of layers where the HttpResponseException is converted back to HttpResponseMessage, and one of those places is right after the action method finishes executing. The reason for this design is that HttpResponseException is not really meant to represent an exceptional situation. Instead, it's a way of returning a HttpResponseMessage from a place in code that would not otherwise support returning that type. Since filters have a way of returning a HttpResponseMessage, throwing HttpResponseException from them is not advised. Ideally, we would have code to convert HttpResponseException into HttpResponseMessage after every location where we call into user code, but considering the sheer number of extensibility points that's not really feasible.
As user mentions, when throwing HttpResponseException at the controller's action, exception filter is not executed...but throwing at an action filter is causing the exception filter to be executed.
I was able to repro this issue.
Following is repro code:
```
using System;
using System.Configuration;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Web.Http.SelfHost;
namespace Service
{
class Service
{
private static HttpSelfHostServer server = null;
private static AppSettingsReader appSettingsReader = null;
static void Main(string[] args)
{
appSettingsReader = new AppSettingsReader();
string baseAddress = string.Format("http://{0}:9095/", Environment.MachineName);
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
try
{
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Service listenting at: {0} ...", baseAddress);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Exception Details:\n{0}", ex.ToString());
}
finally
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
}
public class SampleController : ApiController
{
[TestActionFilter]
[TestExceptionFilter]
public string Get()
{
//throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest, "bad data"));
return "Hello";
}
public string Post([FromBody] string input)
{
return input;
}
}
public class TestActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
throw new HttpResponseException(actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, "bad data"));
}
}
public class TestExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
Console.WriteLine("Exception type" + actionExecutedContext.Exception.GetType().ToString());
}
}
}
```
Comments: This was an intentional implementation. The HttpResponseException is a way to short-circuit the request processing pipeline and return a HttpResponseMessage. There are a number of layers where the HttpResponseException is converted back to HttpResponseMessage, and one of those places is right after the action method finishes executing. The reason for this design is that HttpResponseException is not really meant to represent an exceptional situation. Instead, it's a way of returning a HttpResponseMessage from a place in code that would not otherwise support returning that type. Since filters have a way of returning a HttpResponseMessage, throwing HttpResponseException from them is not advised. Ideally, we would have code to convert HttpResponseException into HttpResponseMessage after every location where we call into user code, but considering the sheer number of extensibility points that's not really feasible.