ASP.NET / Mono MVC4 Web API v.1 application.
API controllers are using Forms authorication and are decorated with standard [Authorize]
attribute.
If authorization fails, standard api error message
<Error>
<Message>Authorization has been denied for this request.</Message>
</Error>
occurs.
How to itercept this error for sriting to log file .
Error message returned to caller shoudl remain the same.
how to add additional code to this which can wrote this error message with whole http
request headers and body to log file ?
I added code from question
How do I log ALL exceptions globally for a C# MVC4 WebAPI app?
and from
How to catch undefined api method calls in ASP.NET MVC4 Web API
but athorization error is not catched.
How to catch all errors ?
Update
code needs to run in Windows 2003 server.
I tried code from answer but got compile errors
Predefined type 'System.Runtime.CompilerServices.IAsyncStateMachine' is not defined or imported
Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?
Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?
How to run int in W2003 server ?
One way you could achieve this is to write a DelegatingHandler to intercept the response before it gets sent back to the client, and then log information on those requests that return errors.
public class RepsonseInterceptor : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
LogResponse(request, response);
return response;
}
public void LogResponse(HttpRequestMessage request, HttpResponseMessage response)
{
HttpStatusCode status = response.StatusCode;
//Catch the status codes you want to Log
if (status == HttpStatusCode.NotFound || status == HttpStatusCode.Unauthorized || status == HttpStatusCode.InternalServerError)
{
//Do Logging Stuff here
//with the Request and Response
}
}
}
Then add this to the Application_Start in the Global.asax.cs:
GlobalConfiguration.Configuration.MessageHandlers.Add(new ResponseInterceptor());
EDIT:
If you don't want to execute the handler for all routes you can add it as a Per-Route Message Handler to those routes you want instead of globally like so:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: null,
handler: new ResponseInterceptor()
);
If you are using .NET Framework 4.0 you need to change the SendAsync method of the handler as follows:
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
LogResponse(request, response);
return response;
});
}
I think it would be reasonable to just use this MessageHandler if you can obtain all of the information that you need to log from the Request and Response objects, although I've not fully tested this out.