Exception handling in Controller (ASP.NET MVC) - c#

When an exception is thrown by your own code that's called from an action in a controller how should that be handled? I see a lot of examples of best practices where there are no try-catch statements at all. For example, accessing data from a repository:
public ViewResult Index()
{
IList<CustomModel> customModels = _customModelRepository.GetAll();
return View(customModels);
}
Clearly this code could throw an exception if the call is to a database that it can't access and we are using an ORM like Entity Framework for example.
However all that I can see will happen is that the exception will bubble up and show a nasty error message to the user.
I'm aware of the HandleError attribute but I understand it's mostly used to redirect you to an error page if an exception that's unhandled occurs.
Of course, this code could be wrapped in a try-catch but doesn't separate nicely, especially if you have more logic:
public ViewResult Index()
{
if (ValidationCheck())
{
IList<CustomModel> customModels = new List<CustomModel>();
try
{
customModels = _customModelRepository.GetAll();
}
catch (SqlException ex)
{
// Handle exception
}
if (CustomModelsAreValid(customModels))
// Do something
else
// Do something else
}
return View();
}
Previously I have extracted out all code that could throw exceptions like database calls into a DataProvider class which handles errors and returns messages back for showing messages to the user.
I was wondering what the best way of handling this is? I don't always want to return to an error page because some exceptions shouldn't do that. Instead, an error message to the user should be displayed with a normal view. Was my previous method correct or is there a better solution?

I do three things to display more user-friendly messages:
Take advantage of the global exception handler. In the case of MVC: Application_Error in Global.asax. Learn how to use it here: http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
I subclass Exception into a UserFriendlyException. I do my very best in all of my underlying service classes to throw this UserFriendlyException instead of a plain old Exception. I always try to put user-meaningful messages in these custom exceptions. The main purpose of which is to be able to do a type check on the exception in the Application_Error method. For the UserFriendlyExceptions, I just use the user-friendly message that I've set deep down in my services, like "Hey! 91 degrees is not a valid latitude value!". If it's a regular exception, then it's some case I haven't handled, so I display a more generic error message, like "Oops, something went wrong! We'll do our best to get that fixed!".
I also create an ErrorController that is responsible for rendering user-friendly views or JSON. This is the controller whose methods will be called from the Application_Error method.
EDIT:
I thought I'd give a mention to ASP.NET Web API since it's closely related. Because the consumer of Web API endpoints won't necessarily be a browser, I like to deal with errors a little differently. I still use the "FriendlyException" (#2 above), but instead of redirecting to an ErrorController, I just let all my endpoints return some kind of base type that contains an Error property. So, if an exception bubbles all the way up to the Web API controllers, I make sure to stick that error in the Error property of API response. This error message will either be the friendly message that has bubbled up from the classes the API controller relies on, or it will be a generic message if the exception type is not a FriendlyException. That way, the consuming client can simply check whether or not the Error property of the API response is empty. Display a message if the error is present, proceed as usual if not. The nice thing is that, because of the friendly message concept, the message may be much more meaningful to the user than a generic "Error!" message. I use this strategy when writing mobile apps with Xamarin, where I can share my C# types between my web services and my iOS/Android app.

With Asp.Net MVC you can also override the OnException method for you controller.
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
filterContext.Result = new ViewResult
{
ViewName = ...
};
filterContext.ExceptionHandled = true;
}
This allow you to redirect to a custom error page with a message that refer to the exception if you want to.

I used an OnException override because I have several projects referenes to one that have a Controller that handle errors:
Security/HandleErrorsController.cs
protected override void OnException(ExceptionContext filterContext)
{
MyLogger.Error(filterContext.Exception); //method for log in EventViewer
if (filterContext.ExceptionHandled)
return;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
Data = new
{
Success = false,
Error = "Please report to admin.",
ErrorText = filterContext.Exception.Message,
Stack = filterContext.Exception.StackTrace
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.ExceptionHandled = true;
}

All questions like this are not very constructive, because the answer is always "it depends", because there are so many ways of dealing with error handling.
Many people like to use the HandleError method, because any exception is basically non-recoverable. I mean, what are you going to do if you can't return the objects? You're going to show them an error anyways, right?
The question becomes, how you want to show them the error. If showing them an error page is acceptable, than HandleError works fine, and provides an easy place to log the error. If you're using Ajax or want something fancier, then you need to develop a way to do that.
You talk about a DataProvider class. That's basically what your Repository is. Why not build that into your repository?

Related

Ensure that a specific exception always results in a given HTTP response status code

Requirement
I have an ASP.Net MVC application that works with a number of different libraries. As with most libraries, various function calls may cause one of many different exceptions to be thrown.
Currently, whenever any exception is thrown, then MVC application 'handles' them and returns an "internal server error" (code 500) back to the client (eg. web browser).
This is fine for most cases, however, there is one specific exception type (in this case UnauthorizedAccessException) that I would like to result in an "Unauthorized" (code 401) status being sent in the response, instead of the usual 500 error.
Current Attempt
I did a fair bit of research and it looks like the bets way to 'catch' all exceptions and process them is by using the Application_Error method. So I tried the following implementation of Application_Error in the MvcApplication class:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if(ex is UnauthorizedAccessException)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
}
}
Problem
The problem here is that although I can debug and see that Response.StatusCode is being set to 401, the client/browser is still receiving a 500 error.
I expect that there is a very good reason why this is happening, but I have exhausted my brain thinking of search terms that will get me the answer I need.
Question
In short, what do I need to do in order to get the behaviour I am looking for?
For additional information, ultimately what I want is for an UnauthorizedAccessException to have the same behaviour as how MVC handles unauthenticated requests (which redirects to login page). However, I also need it to work for AJAX requests in that my javascript can check for 401 error and do some specific logic (in which case a response redirect to login page is not workable)
A clever way to go about doing that is to create a Base Controller that your controllers inherit over the default Controller. There you inherit the default Controller class and override the OnException method.
public abstract class BaseController : Controller
{
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
var responseCode = Response.StatusCode;
var exception = filterContext.Exception;
switch (exception.GetType().ToString())
{
case "UnauthorizedAccessException":
responseCode = 401;
filterContext.ExceptionHandled = true;
break;
}
Response.StatusCode = responseCode;
base.OnException(filterContext);
}
}
The trick that makes it work is filterContext.ExceptionHandled = true; if you don't set this to true, the server will return 500.
Your controllers will inherit the BaseController;
public class UserController : BaseController
{
public ActionResult Index(){
return View();
}
}
What you'll need to add to this code is your redirect to the login page, to your OnException method (if needed). I would do it for you but I don't have enough time to write and test it for you.. currently waiting for automated tests to finish.. :-)
Edit:
I did not realize your view could throw errors too, that obviously won't be handled by the controller.
In this case we can revert to the original Application_Error method on Global.asax.
What we need is two lines of code..
Response.StatusCode = 401;
Response.End();
First line sets the status code to 401,
Second line ends the execution at this point and triggers EndRequest event, so the StatusCode won't be modified to 500.
If you want to attach a message with your response:
Response.Write("Oops, you're not authorized...");
It would be a good idea to call Response.Clear(); before starting to modify the response object inside your Error Handler.

Asp.Net WebApi catch exceptions generated in controller constructor

In my base API controller class constructor, I am populating user permissions based on windows authentication. I am using something like
var ctx = new PrincipalContext(ContextType.Domain, System.Environment.UserDomainName.ToUpper());
var userInfo = UserPrincipal.FindByIdentity(ctx, System.Environment.UserName.ToUpper());
to get user information from AD. The problem is that when the user is locked out the application is failing with 500 since the exception occurs in the constructor. Is there a way to handle the exception of these calls and bubble it up as an Unauthorized exception or something else? I tried to surround it with try catch and throw httpresponse exception with unauthorized but it still bubbles up as 500.
edit #1
There are few more things happening in constructor and when it is failing I do not want to fail with 500. I need to catch the exception and throw something else. Authorization was just an example of one of those few things.
edit #2
To all who write that I should not have any logic in the constructor:
Constructors are used to initialize the object to a valid state. The controller of this part of the application has to have a database connection, user information and some other properties populated because all of the requests are using all this information. If any of those is failing I want to return a different type of the error to the user. In the case of a standard class it would be different type of exceptions (SqlException, DbConnectionException, Some sort of AD Exception). In the case of WebApi I want it to be a different type of the response codes (Unauthorized, Not Implemented (501) etc). Copy pasting the same code to every request in that section of the application represents a maintenance issue.
Since the original exception is wrapped into other exceptions few times the only way I found so far is to have a global exception filter and then navigate through the inner exceptions of the context. Exception till it is null or I didn't reach the exception of the type I am looking for.
namespace SomeWebApi
{
public class GlobalExceptionHandler : ExceptionHandler
{
public override async Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context.Exception != null)
{
Exception filteredException = context.Exception;
while (
(filteredException != null)
&&
(filteredException.GetType() != typeof(HttpResponseException)
)
{
filteredException = filteredException.InnerException ;
}
if (
(filteredException != null)
&&
(filteredException != context.Exception)
)
{
var httpResponseException = (HttpResponseException) filteredException;
var response = context.Request.CreateErrorResponse(
httpResponseException.Response.StatusCode,
httpResponseException
);
context.Result = new ResponseMessageResult(response);
}
}
}
}
}
Next I needed to register it in WebApiConfig.Register:
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
The eseaiest way is to not use user / sesion related logic in controllers constructor.
For authentication You can use attribute filters, for geting user information just create helper class and use it when needed.
edit
one last thing: try to use dependency injection (like structure map) it will force You to make proper changes in constructor and it will make initializing easier. https://www.exceptionnotfound.net/setting-up-dependency-injection-in-web-api-with-structuremap/

Handle 'underlying provider failed on open' in one place

I have an MVC Razor application that uses entity framework 6.0. However, if the DB is down or something, my code starts throwing exceptions at all kinds of random places like when I start evaluating my IEnumerable<T>s and IQueryable<T>s.
The model constructor is generated code that will be overwritten if I modify it which wouldn't help anyway because the constructor doesn't throw exceptions. Instead, the exceptions come in places like this
using (var dataContext = new ArchiveVMADDatabase.ArchiveDatabaseModel())
{
IQueryable<HDeploy> deploys = Helpers.GetProdDeploysFromArchive(dataContext);
var query = getBranchSelectListQuery(deploys);
listItems.AddRange(query);// EXCEPTION IF DB IS DOWN
}
Is there a good way for me to handle this in one place and avoid wrapping nearly 100% of my code in giant try catch blocks? I would really like to have it just return empty sets if it can't talk to the DB.
I'm not sure whether you are working with MVC or Web API, but in Web API one would use Exception Filters to centralize exception handling.
An exception filter is basically a derivative of the ExceptionFilterAttribute that can create a specific response depending on the caught exception:
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
You don't need to add try {} catch {} blocks anywhere -- Web API triggers the configured exception filters automatically as soon as an exception reaches the outer most layer of your system (i.e. the controller level).
You can activate an exception filter only for specific ApiControllers or globally for every controller.

Exceptions in validation

I currently have some code that delibratly throws an exception if the user sends me data that fails validation (see below). I like it because im sure any errors in the application are caught and handled. A am however worried the code being slow as throwing exceptions takes a lot of memory. Im also worried it might be "bad code". Whats your advice? Thanks
public class BTAmendAppointmentRequest
{
public DataLayer.WebserviceMessage AddBTAmendAppointmentRequest(DataLayer.BTAmendAppointmentRequest req)
{
DataLayer.WebserviceMessage rsp = new DataLayer.WebserviceMessage();
try
{
if (!String.IsNullOrEmpty(req.AppointmentReference))
req.AppointmentReference = req.AppointmentReference.Trim();
if (req.OrderRequestID < 1 || string.IsNullOrEmpty(req.AppointmentReference))
{
throw new Exception("Amend appointment failed, you must supply a valid appointment reference and order reference");
}
...Do other stuff
}
catch (Exception ex)
{
rsp = new Service.WebserviceErrorMessage(ex);
}
return rsp;
}
}
If you are expecting these errors, you should return error messages to the user, not throw exceptions.
Reserve exceptions to exceptional situations.
Apart from being expensive, the meaning of an exception, the semantics are that of something exceptional having happened. Validation failing is not exceptional, it is expected.
Having said that, seeing as you are on a web service, an exception is a reasonable thing to do, assuming you also validate before the service call. It is reasonable since a web service can be called by anything - validation may not have happened, and such errors should be exceptional. Additionally, at least with .NET web services, web exceptions are probably the best way to communicate such things back to the client.
Exceptions should be considered as last resort error trap. They should be "exceptional". Data input errors are not exceptions - they are very common, expected events. You shoudl handle validation issues with validation controls or processes, that handle them - display an error message and do not let the processing continue.
Your other problem is that you cannot easily do full form validation if the first error you encounter throws an exception. If I was filling out a form where each error was separately highlighted, I would give up very quickly. You need to be able to validate and display ALL errors on a page, and not permit progress without validation succeeding.
I tend to agree with Oded in that exceptions should only be used for stuff you aren't expecting. The other way to look at it is with using an errors collection, you are able to validate a larger batch instead of throwing an exception on the first problem. This can be more usable for the person consuming your service.
In the case of web services, I would package the entire response in a custom response object, which features a return code. This allows you to have a return code of error, and then encapsulate an errors collection in the response object.

Easy way to catch all unhandled exceptions in C#.NET

I have a website built in C#.NET that tends to produce a fairly steady stream of SQL timeouts from various user controls and I want to easily pop some code in to catch all unhandled exceptions and send them to something that can log them and display a friendly message to the user.
How do I, through minimal effort, catch all unhandled exceptions?
this question seems to say it's impossible, but that doesn't make sense to me (and it's about .NET 1.1 in windows apps):
All unhandled exceptions finally passed through Application_Error in global.asax. So, to give general exception message or do logging operations, see Application_Error.
If you need to catch exeptions in all threads the best aproach is to implement UnhandledExceptionModule and add it to you application look here
for an example
Use the Application_Error method in your Global.asax file. Inside your Application_Error method implementation call Server.GetLastError(), log the details of the exception returned by Server.GetLastError() however you wish.
e.g.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
log4net.ILog log = log4net.LogManager.GetLogger(typeof(object));
using (log4net.NDC.Push(this.User.Identity.Name))
{
log.Fatal("Unhandled Exception", Server.GetLastError());
}
}
Don't pay too much attention to the log4net stuff, Server.GetLastError() is the most useful bit, log the details however you prefer.
The ELMAH project sounds worth a try, its list of features include:
ELMAH (Error Logging Modules and
Handlers) is an application-wide error
logging facility that is completely
pluggable. It can be dynamically added
to a running ASP.NET web application,
or even all ASP.NET web applications
on a machine, without any need for
re-compilation or re-deployment.
Logging of nearly all unhandled exceptions.
A web page to remotely view the entire log of recoded exceptions.
A web page to remotely view the full details of any one logged
exception.
In many cases, you can review the original yellow screen of death that
ASP.NET generated for a given
exception, even with customErrors mode
turned off.
An e-mail notification of each error at the time it occurs.
An RSS feed of the last 15 errors from the log.
A number of backing storage implementations for the log
More on using ELMAH from dotnetslackers
You can subscribe to the AppDomain.CurrentDomain.UnhandledException event.
It's probably important to note that you are not supposed to catch unhandled exceptions. If you are having SQL timeout issues, you should specifically catch those.
Do you mean handling it in all threads, including ones created by third-party code? Within "known" threads just catch Exception at the top of the stack.
I'd recommend looking at log4net and seeing if that's suitable for the logging part of the question.
If using .net 2.0 framework, I use the built in Health Monitoring services. There's a nice article describing this method here: https://web.archive.org/web/20210305134220/https://aspnet.4guysfromrolla.com/articles/031407-1.aspx
If you're stuck with the 1.0 framework, I would use ELMAH:
http://msdn.microsoft.com/en-us/library/aa479332.aspx
hope this helps
There are 2 parts to this problem handling & identifying.
Identifying
This is what you do when the exception is finally caught, not necessarily where it is thrown. So the exception at that stage must have enough context information for you to idenitfy what the problem was
Handling
For handling, you can
a) add a HttpModeule. See
http://www.eggheadcafe.com/articles/20060305.asp
I would suggest this approach only when there is absolutely no context informaatn available and there might be issuus wiih IIS/aspnet, In short for catastrophic situations
b) Create a abstract class called AbstractBasePage which derives from Page class and have all your codebehind classes derive from AbstractBasePage
The AbstractBasePage can implement that Page.Error delegate so that all exceptions which percolate up through the n-tier architecture can be caught here(and possibly logged)
I would suggest this cause for the kind of exceptions you are talking about (SQlException) there is enough context information for you to identify that it was a timeout and take possible action. This action might include redirecting user to a custom error page with appropriate message for each different kind of exception (Sql, webservice, async call timeouts etc).
Thanks
RVZ
One short answer is to use (Anonymous) delegate methods with common handling code when the delegate is invoked.
Background: If you have targeted the weak points, or have some boilerplate error handling code you need to universally apply to a particular class of problem, and you don't want to write the same try..catch for every invocation location, (such as updating a specific control on every page, etc).
Case study: A pain point is web forms and saving data to the database. We have a control that displays the saved status to the user, and we wanted to have common error handling code as well as common display without copy-pasting-reuse in every page. Also, each page did it's own thing in it's own way, so the only really common part of the code was the error handling and display.
Now, before being slammed, this is no replacement for a data-access layer and data access code. That's all still assumed to exist, good n-tier separation, etc. This code is UI-layer specific to allow us to write clean UI code and not repeat ourselves. We're big believers in not quashing exceptions, but certain exceptions shouldn't necessitate the user getting a generic error page and losing their work. There will be sql timeouts, servers go down, deadlocks, etc.
A Solution: The way we did it was to pass an anonymous delegate to a method on a custom control and essentially inject the try block using anonymous delegates.
// normal form code.
private void Save()
{
// you can do stuff before and after. normal scoping rules apply
saveControl.InvokeSave(
delegate
{
// everywhere the save control is used, this code is different
// but the class of errors and the stage we are catching them at
// is the same
DataContext.SomeStoredProcedure();
DataContext.SomeOtherStoredProcedure();
DataContext.SubmitChanges();
});
}
The SaveControl itself has the method like:
public delegate void SaveControlDelegate();
public void InvokeSave(SaveControlDelegate saveControlDelegate)
{
// I've changed the code from our code.
// You'll have to make up your own logic.
// this just gives an idea of common handling.
retryButton.Visible = false;
try
{
saveControlDelegate.Invoke();
}
catch (SqlTimeoutException ex)
{
// perform other logic here.
statusLabel.Text = "The server took too long to respond.";
retryButton.Visible = true;
LogSqlTimeoutOnSave(ex);
}
// catch other exceptions as necessary. i.e.
// detect deadlocks
catch (Exception ex)
{
statusLabel.Text = "An unknown Error occurred";
LogGenericExceptionOnSave(ex);
}
SetSavedStatus();
}
There are other ways to achieve this (e.g. common base class, intefaces), but in our case this had the best fit.
This isn't a replacement to a great tool such as Elmah for logging all unhandled exceptions. This is a targeted approach to handling certain exceptions in a standard manner.
Timeout errors typically occur if you are not forcefully closing your sqlconnections.
so if you had a
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
}
If anything goes wrong with that ExecuteReader your connection will not be closed. Always add a finally block.
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
} finally {
if(conn.State != ConnectionState.Closed)
conn.Close();
}
This is old question, but the best method (for me) is not listed here. So here we are:
ExceptionFilterAttribute is nice and easy solution for me. Source: http://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling.
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var exception = context.Exception;
if(exception is SqlTimeoutException)
{
//do some handling for this type of exception
}
}
}
And attach it to f.e. HomeController:
[ExceptionHandling]
public class HomeController: Controller
{
}

Categories

Resources