log4net catch all controller action errors for web api - c#

I am currently implementing log4net for catching my exceptions for web api controller.
I wanted to know how could i potentially catch all errors in any action within the controller?
I did not want to go through each action ideally and add try catch if it can be helped?

You need to register an IExceptionLogger
e.x.: GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new YourWebApiExceptionLogger());

You can implement a System.Web.Http.Filters.ActionFilterAttribute. In the OnActionExecuted you can handle your logging:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Response != null)
{
//ok
}
else
{
_logger.ErrorFormat("actionExecutedContext.Response == null will result in 500, unhandled exception"); //Add extra information here
}
}
Then you can add this ActionFilter as attribute to the methods you want to log.

Related

Web API 2 services - how to return an Exception message in the Status

Is it possible, in Web API 2 to directly return the Exception message in the response's Status ?
For example, if I was writing a WCF Service (rather than Webi API), I could follow this tutorial to directly return an Exception message as part of the response status:
Here, the web service doesn't return any data in the Response, and the error message gets returned directly in the Status Description.
This is exactly what I'd like my Web API services to do when an exception occurs, but I can't work out how to do it.
Most suggestions suggest using code like below, but then the error message will then always get returned in a separate response string, rather than being part of the Status.
For example, if I were to use this code:
public IHttpActionResult GetAllProducts()
{
try
{
// Let's get our service to throw an Exception
throw new Exception("Something went wrong");
return Ok(products);
}
catch (Exception ex)
{
return new System.Web.Http.Results.ResponseMessageResult(
Request.CreateErrorResponse((HttpStatusCode)500,
new HttpError("Something went wrong")));
}
}
... then it returns a generic 500 message, and the exception is returned in a JSON string.
Does anyone know how to modify a Web API function (which returns an IHttpActionResult object) to do this ?
You could register a custom global filter that will handle all Exceptions. Something like:
public class CatchAllExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
}
}
You will need to register it in WebApiConfig.cs, with:
config.Filters.Add(new CatchAllExceptionFilterAttribute());
This filter will be hit everytime there is an unhandled exception in the system and set the http response to the exception message. You could also check the different types of exception and alter your response accordingly, for example:
public override void OnException(HttpActionExecutedContext context)
{
if(context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented)
{
Content = new StringContent("Method not implemented.")
};
}
else
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
}
}
https://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling
Please refer above link, it will help you!

MVC error handling in Owin Middleware

When certain exceptions are thrown in controllers, I want to catch those exceptions and do some extra logic.
I was able to achieve this with a custom IExceptionFilter that is added to the global filters list.
However, I preffer to handle these exception within a custom Owin middleware.
My middleware looks like this:
try
{
await Next.Invoke(context);
}
catch (AdalSilentTokenAcquisitionException e)
{
//custom logic
}
This piece of code does not work, it looks like the exception is already catched and handled in MVC.
Is there a way to skip the exception processing from MVC and let the middleware catch the exception?
Update: I've found a cleaner approach, see my updated code below.
With this approach, you don't need a custom Exception Filter and best of all, you don't need the HttpContext ambient service locator pattern in your Owin middleware.
I have a working approach in MVC, however, somehow it doesn't feel very comfortable, so I would appreciate other people's opinion.
First of all, make sure there are no exception handlers added in the GlobalFilters of MVC.
Add this method to the global asax:
protected void Application_Error(object sender, EventArgs e)
{
var lastException = Server.GetLastError();
if (lastException != null)
{
HttpContext.Current.GetOwinContext().Set("lastException", lastException);
}
}
The middleware that rethrows the exception
public class RethrowExceptionsMiddleware : OwinMiddleware
{
public RethrowExceptionsMiddleware(OwinMiddleware next) : base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
var exception = context.Get<Exception>("lastException");
if (exception != null)
{
var info = ExceptionDispatchInfo.Capture(exception);
info.Throw();
}
}
}
There's no perfect way to do this (that I know of), but you can replace the default IExceptionHandler with one that just passes the error through to the rest of the stack.
I did some extensive digging about this, and there really doesn't seem to be a better way for now.

code duplication in try catch block

Is there a better way to catch exceptions? I seem to be duplicating a lot of code. Basically in every controller I have a catch statement which does this:
try
{
Do something that might throw exceptions.
}
catch (exception ex)
{
Open database connection
Save exception details.
If connection cannot be made to the database save exception in a text file.
}
I have 4 controllers and around 5-6 actions methods in each controller which is a lot of code duplication. How can I trim down on the amount of line in the try catch statement above?
You could make use of Extension methods here.
Create an extension method in a new class.
public static class ExtensionMethods
{
public static void Log(this Exception obj)
{
// log your Exception here.
}
}
And use it like:
try
{
}
catch (Exception obj)
{
obj.Log();
}
You don't need to put try/catch blocks on every method. That's tedious and painful! Instead you can use the Application_Error event of Global.asax for logging the exceptions. The code below is the sample implementation which can be used to catch exceptions that occur in your web application.
protected void Application_Error(object sender, EventArgs e)
{
var error = Server.GetLastError();
if (!string.IsNullOrWhiteSpace(error.Message))
{
//do whatever you want if exception occurs
Context.ClearError();
}
}
I would like also to stress that "Handled exception" especially trying to put try/catch blocks on most methods is one of the "Top 3 silent performance killers for IIS / ASP.NET apps" as explained in this blog http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/
What you are trying to do is called a cross-cutting concern. You are trying to log any error that happens anywhere in your code.
In ASP.NET MVC cross-cutting concerns can be achieved by using Filters. Filters are attributes that can be applied globally, to a controller or to a method. They run before an action method executes or after it.
You have several types of filters:
Authorization filters, they run to check if the user is allowed to access a resource.
Action filters, these run before and after an action method executes.
Result filters, these can be used to change the result of an action method (for example, add some extra HTMl to the output)
Exception filters run whenever an exception is thrown.
In your case, you are looking for exception filters. Those filters only run when an exception happens in in an action method. You could apply the filter globally so it will automatically run for all exceptions in any controller. You can also use it specifically on certain controllers or methods.
Here in the MSDN documentation you can find how to implement your own filters.
Personally, since I greatly dislike try/catch blocks, I use a static Try class that contains methods that wrap actions in reusable try/catch blocks. Ex:
public static class Try {
bool TryAction(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostException(exception);
return false;
}
}
bool TryQuietly(Action pAction) {
try {
pAction();
return true;
} catch (Exception exception) {
PostExceptionQuietly(exception);
return false;
}
}
bool TrySilently(Action pAction) {
try {
pAction();
return true;
} catch { return false; }
}
// etc... (lots of possibilities depending on your needs)
}
I have used a special class in my applications that is called ExceptionHandler, in the class that is static I have some methods to handle application's exceptions. It gives me an opportunity to centralize exception handling.
public static class ExceptionHandler
{
public static void Handle(Exception ex, bool rethrow = false) {...}
....
}
In the method you can log the exception, rethrow it, replace it with another kind of exception, etc.
I use it in a try/catch like this
try
{
//Do something that might throw exceptions.
}
catch (exception ex)
{
ExceptionHandler.Handle(ex);
}
As Wouter de Kort has rightly stated in his answer, it is cross-cutting concern, so I've put the class in my Application Layer and have used it as a Service. If you defined the class as an interface you would be able to have different implementations of it in different scenarios.
Also you can use Singleton pattern:
sealed class Logger
{
public static readonly Logger Instance = new Logger();
some overloaded methods to log difference type of objects like exceptions
public void Log(Exception ex) {}
...
}
And
Try
{
}
Catch(Exception ex)
{
Logger.Instance.Log(ex);
}
Edit
Some peoples don't like Singleton for reasonable grounds.instead of singleton we can use some DI:
class Controller
{
private ILogger logger;
public Controller(ILogger logger)
{
this.logger = logger;
}
}
And use some DI library that will inject one instance of ILogger into your controllers.
I like the answers suggesting general solutions, however I would like to point out another one which works for MVC.
If you have a common controller base (wich you should anyways, it's a Best Practice IMO). You can simply override the OnException method:
public class MyControllerBase : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
DoSomeSmartStuffWithException(filterContext.Exception);
base.OnException(filterContext);
}
}
Then simply inherit your normal controllers from your common base instead of Controller
public class MyNormalController : MyControllerBase
{
...
If you like this you can check out the Controller class for other handy virtual methods, it has many.
In ASP .NET MVC you can implement your own HandleErrorAttribute to catch all the exceptions that occur in all controllers:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var ex = filterContext.Exception;
// Open database connection
// Save exception details.
// If connection cannot be made to the database save exception in a text file.
}
}
Then register this filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
}
}
And of-course call the register method on application start-up:
public class MvcApplication : HttpApplication
{
protected override void OnApplicationStarted()
{
// ...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ...
}
}
Wouter de Kort has already explained the concept behind this in his answer.

catch all unhandled exceptions in ASP.NET Web Api

How do I catch all unhandled exceptions that occur in ASP.NET Web Api so that I can log them?
So far I have tried:
Create and register an ExceptionHandlingAttribute
Implement an Application_Error method in Global.asax.cs
Subscribe to AppDomain.CurrentDomain.UnhandledException
Subscribe to TaskScheduler.UnobservedTaskException
The ExceptionHandlingAttribute successfully handles exceptions that are thrown within controller action methods and action filters, but other exceptions are not handled, for example:
Exceptions thrown when an IQueryable returned by an action method fails to execute
Exceptions thrown by a message handler (i.e. HttpConfiguration.MessageHandlers)
Exceptions thrown when creating a controller instance
Basically, if an exception is going to cause a 500 Internal Server Error to be returned to the client, I want it logged. Implementing Application_Error did this job well in Web Forms and MVC - what can I use in Web Api?
This is now possible with WebAPI 2.1 (see the What's New):
Create one or more implementations of IExceptionLogger. For example:
public class TraceExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
Trace.TraceError(context.ExceptionContext.Exception.ToString());
}
}
Then register with your application's HttpConfiguration, inside a config callback like so:
config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
or directly:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
To answer my own question, this isn't possible!
Handling all exceptions that cause internal server errors seems like a basic capability Web API should have, so I have put in a request with Microsoft for a Global error handler for Web API:
https://aspnetwebstack.codeplex.com/workitem/1001
If you agree, go to that link and vote for it!
In the meantime, the excellent article ASP.NET Web API Exception Handling shows a few different ways to catch a few different categories of error. It's more complicated than it should be, and it doesn't catch all interal server errors, but it's the best approach available today.
Update: Global error handling is now implemented and available in the nightly builds! It will be released in ASP.NET MVC v5.1. Here's how it will work: https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
The Yuval's answer is for customizing responses to unhandled exceptions caught by Web API, not for logging, as noted on the linked page. Refer to the When to Use section on the page for details. The logger is always called but the handler is called only when a response can be sent. In short, use the logger to log and the handler to customize the response.
By the way, I am using assembly v5.2.3 and the ExceptionHandler class does not have the HandleCore method. The equivalent, I think, is Handle. However, simply subclassing ExceptionHandler (as in Yuval's answer) does not work. In my case, I have to implement IExceptionHandler as follows.
internal class OopsExceptionHandler : IExceptionHandler
{
private readonly IExceptionHandler _innerHandler;
public OopsExceptionHandler (IExceptionHandler innerHandler)
{
if (innerHandler == null)
throw new ArgumentNullException(nameof(innerHandler));
_innerHandler = innerHandler;
}
public IExceptionHandler InnerHandler
{
get { return _innerHandler; }
}
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
Handle(context);
return Task.FromResult<object>(null);
}
public void Handle(ExceptionHandlerContext context)
{
// Create your own custom result here...
// In dev, you might want to null out the result
// to display the YSOD.
// context.Result = null;
context.Result = new InternalServerErrorResult(context.Request);
}
}
Note that, unlike the logger, you register your handler by replacing the default handler, not adding.
config.Services.Replace(typeof(IExceptionHandler),
new OopsExceptionHandler(config.Services.GetExceptionHandler()));
You can also create a global exception handler by implementing the IExceptionHandler interface (or inherit the ExceptionHandler base class). It will be the last to be called in the execution chain, after all registered IExceptionLogger:
The IExceptionHandler handles all unhandled exceptions from all
controllers. This is the last in the list. If an exception occurs, the
IExceptionLogger will be called first, then the controller
ExceptionFilters and if still unhandled, the IExceptionHandler
implementation.
public class OopsExceptionHandler : ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong."
};
}
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
More on that here.
You may have existing try-catch blocks that you're not aware of.
I thought my new global.asax.Application_Error method wasn't being consistently called for unhandled exceptions in our legacy code.
Then I found a few try-catch blocks in the middle of the call stack that called Response.Write on the Exception text. That was it. Dumped the text on the screen then killed the exception stone dead.
So the exceptions were being handled, but the handling was doing nothing useful. Once I removed those try-catch blocks the exceptions propagated to the Application_Error method as expected.

How can I map directly from my Application-specific exceptions to Http Exceptions?

I am working on a ASP.NET MVC 3 application. In the so-called "Business Layer" of our App, we have made a decision to always throw some specific types of exceptions depending on the situation. We have an Exception type hierarchy when a user tries supposed to do something he is not authorized, and special exceptions when the application cannot find a given item (by Id or name or whatever).
This looks like this in our C# Code :
// ... more stuff
public Something GetSomething(int id, User currentUser){
var theSomething = SomethingRepository.Get(id);
if(theSomething == null){
throw new SomethingNotFoundException(id, "more details");
}
if(!PermissionService.CanLoadSomething(currentUser)){
throw new NotAuthorizedException("You shall not pass");
}
// the rest of the method etc etc
// ...
}
... where SomethingNotFoundException and NotAuthorizedException are custom Exceptions .
There is somehow a direct mapping between this kind of exceptions and the Http Status Code (404 Not Found / 403 Forbidden), and we would like our Controller methods to handle those errors accordingly (showing the 404/403 CustomError pages and things like that). Now, what we want is to avoid having to do this in our controller actions :
public ViewResult Get(int id){
try{
var theSomething = MyService.GetSomething(id, theUser);
}
catch(SomethingNotFoundException ex){
throw new HttpException(404, ex);
}
catch(NotAuthorizedExceptionex){
throw new HttpException(403, ex);
}
}
I am pretty sure there must be a way to use either a custom HandleErrorAttribute or a custom ActionFilterAttribute and register it in the Global.asax, but I cannot figure out how to have it working .
Attempt 1 : HandleErrorAttribute
I first tried making a subclass of HandleErrorAttribute, overriding the OnException method as such :
public override void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
Exception exception = filterContext.Exception;
// Map some of the Business Exception to correspounding HttpExceptions !
if (exception is ObjectNotFoundException)
{
// consider it as a NotFoundException !
exception = new HttpException((int)HttpStatusCode.NotFound, "Not found", exception);
filterContext.Exception = exception;
}
else if (exception is NotAuthorizedException)
{
// consider it as a ForbiddenException
exception = new HttpException((int)HttpStatusCode.Forbidden, "Forbidden", exception);
filterContext.Exception = exception;
}
base.OnException(filterContext);
}
... and adding it to the GlobalFilterCollection in Global.asax ... but it is still handled as if it were the usual 500 error, instead of showing the 404/403 custom error pages...
Attempt 2 : ActionFilterAttribute
I also tried making it an ActionFilterAttribute and overriding the OnActionExecuted method like this :
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
Exception exception = filterContext.Exception;
if(exception!=null)
{
// Map some of the Business Exception to correspounding HttpExceptions !
if (exception is ObjectNotFoundException)
{
// consider it as a NotFoundException !
var wrappingException = new HttpException((int)HttpStatusCode.NotFound, "Not found", exception);
exception = wrappingException;
filterContext.Exception = exception;
}
else if (exception is NotAuthorizedException)
{
// consider it as a ForbiddenException
var wrappingException = new HttpException((int)HttpStatusCode.Forbidden, "Forbidden", exception);
exception = wrappingException;
filterContext.Exception = exception;
}
}
base.OnActionExecuted(filterContext);
}
... but still, I get the 500 error page instead of 404 or 403 ...
Am I doing something wrong ? Is there possibly a better way ?
Well there are a few options.
You probably want :This guys solution
You can do it like this This guy.
You could have a base Controller class that all your classes inherit from and use the below method. This is how my last company addressed the issue.
protected override void OnException(ExceptionContext filterContext)
{
Console.WriteLine(filterContext.Exception.ToString());
}

Categories