ASP.NET MVC 5 - Handling Exceptions with some simpler ways

Posted by: Mahesh Sabnis , on 1/7/2015, in Category ASP.NET MVC
Views: 235444
Abstract: ASP.NET MVC provides various ways of handling exceptions. This article helps you decide which exceptions handling mechanism to choose for your requirements.

While developing Line-of-Business (LOB) applications using ASP.NET MVC,  we come across various requirements varying from doing Model Validations to handling Exceptions. MVC already provides Action Filter feature for implementing add-on application logic e.g. request Logging, authorization, HandlerError etc. HandlerError is used to handle exceptions while executing action methods.

We are habitual to make use of try-catch-finally block to handle exceptions, but in case of ASP.NET MVC, while working with action methods we generally write code to redirect to the Index View using RedirectToAction(“Index”). However what if our code encounters an exception and we need to redirect to the Error View? This may be needed with various action methods across various controllers.

 

In the implementation below, I will demonstrate various ways of handling exceptions.

Step 1: Open Visual Studio 2013, (the implementation uses VS 2013 Ultimate with Update 4 although you can very well use the Free Visual Studio Community Edition) and create a new MVC 5 application. Name it as ‘MVC5_Exceptions’.

mvc-app

This creates a MVC project with folders for Models, View, App_Data and Controllers etc. The Views folder has a Shared subfolder with Error.cshtml in it. This is the error view with HandleErrorInfo as model class. This class contains parameterized constructor as shown here:

public HandleErrorInfo(Exception exception, string controllerName, string actionName);

This can be used to pass Exception type, controller and action names to the Error View to display error details. The class also provides properties for Exception, Controller and Action Name. We can make use of these properties to implement logic at view level. (We will anyways see it in the following steps.)

Step 2: In the App_Data folder add a new Sql Server Database of the name Application and create an EmployeeInfo table in it:

CREATE TABLE [dbo].[EmployeeInfo] (
    [EmpNo]       INT          NOT NULL,
    [EmpName]     VARCHAR (50) NOT NULL,
    [DeptName]    VARCHAR (50) NOT NULL,
    [Designation] VARCHAR (50) NOT NULL,
    [Salary]      DECIMAL (18) NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC)
);

Step 3: In the Models folder, right-click and add a new ADO.NET Entity Data Model of the name ApplicationEDMX. In the wizard, select Application.mdf and EmployeeInfo Table. After completion of the wizard, the mapping will be as seen here:

employee-info

Step 4: In the controllers, add a new MVC controller of the name EmployeeInfoController. Now implement action methods, which calls the EF we just created:

public class EmployeeInfoController : Controller
{

    ApplicationEntities ctx;

    public EmployeeInfoController()
    {
        ctx = new ApplicationEntities();  
    }

    // GET: EmployeeInfo
    public ActionResult Index()
    {
       var Emps = ctx.EmployeeInfoes.ToList();
        return View(Emps);
    }

   

    // GET: EmployeeInfo/Create
    public ActionResult Create()
    {
        var Emp = new EmployeeInfo();
        return View(Emp);
    }

    // POST: EmployeeInfo/Create
    [HttpPost]
    public ActionResult Create(EmployeeInfo Emp)
    {

            ctx.EmployeeInfoes.Add(Emp);
            ctx.SaveChanges();

            return RedirectToAction("Index");

    }
}

From the above code, scaffold the Index and Create Views.

 

Implementing Exceptions in ASP.NET MVC apps

As a developer we need to understand and locate the code which has a chance of triggering an exception. Thankfully we have try-catch block to handle exceptions. In ASP.NET MVC, in controller class exceptions can be handled with the following ways:

1. Use try-catch local to each action method.

2. Use and override OnException method of the Controller base class.

3. Handling Exceptions at global level using FilterConfig Class.

Since MVC is a pattern for Web development, as a developer it is our responsibility to think and use the most appropriate options from the above.

Using an easy exception handling mechanism using traditional coding i.e. try-catch

Step 5: In the EmployeeInfoController, change the implementation of the [HttpPost] Create action method as shown here:

[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
    try
    {
        ctx.EmployeeInfoes.Add(Emp);
        ctx.SaveChanges();

        return RedirectToAction("Index");
    }
    catch(Exception ex)
    {
     return View("Error",new HandleErrorInfo(ex,"EmployeeInfo","Create"));
    }
}

In the above code, we are using one of the View() overloads. This accepts the View Name as first parameter and the Model as second. (In the Step 1 we already discussed the Error View and its HandleError Model class). This View will render the Error view. The action method is trying to save EmployeeInfo object using EF, so the type of exception that occurs in the code is of the type DbUpdateException in case of primary key duplicity or any other database update issues.

Step 6: Open Error.Cshtml and add the following code in it:

@model System.Web.Mvc.HandleErrorInfo
<h1 class="text-danger">Error.@Model.Exception.Message</h1>
 
<h2 class="text-danger">An error occurred while processing your request.</h2>

@Html.ActionLink("Back", @Model.ActionName, @Model.ControllerName)

The above CSHTML uses the HandleErrorInfo model object to display error messages in the View.

To test this, run the application and visit the Create view using the following URL:

http://<MyServer>/EmployeeInfo/Create

Enter data into textboxes with the duplicate value for EmpNo. On clicking Submit, the control will be navigated to the error page:

error-page

Once the Back button is clicked, the same create view will be displayed. In the traditional programming this approach looks good with the limitation that the exception code is specific to the action method, so we need to write it in each action method separately.

Implementation of Exception Handling using OnException method overriding of the Controller base class

Controller is the most important component of MVC and plays a major role in request processing. Since Controller Name and Action Name is used in the URL for MVC request processing, we can configure controller to make use of some common logic for execution, which will be used to handle the request. Since exception handling is the part of the request processing, to handle exceptions during action method execution, we can instruct the controller to execute common exception logic. This can be achieved by overriding OnException method of the Controller base class.

Step 1: Open EmployeeInfoController, and override the OnException method:

protected override void OnException(ExceptionContext filterContext)
{
   Exception exception = filterContext.Exception;
   //Logging the Exception
   filterContext.ExceptionHandled = true;


   var Result = this.View("Error", new HandleErrorInfo(exception,
       filterContext.RouteData.Values["controller"].ToString(),
       filterContext.RouteData.Values["action"].ToString()));

   filterContext.Result = Result;
   
}

The above method accepts the ExceptionContext class. This class provides context for using the exception information in the current request processing. This class has Exception property using which the exception occurring during the current action execution can be known. The ExceptionHandled property specifies whether the exception is handled or not. The Result property is used to set the return action. The above code  creates a ViewResult object using View() method of the controller class. To this object, the Error view name and an instance of the HandlerErrorInfo class with Controller and Action Name in the current route using the filterContext object is passed. Finally the ViewResult object is passed to the filterContext object’s Result property to render the Error View.

Step 2: In the EmployeeInfoController class modify the Create method with HttpPost:

[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
    try
    {
        ctx.EmployeeInfoes.Add(Emp);
        ctx.SaveChanges();

        return RedirectToAction("Index");
    }
    catch(Exception ex)
    {
        throw ex;
    }
}

Run the application and try to enter a duplicate record in the EmployeeInfo table using duplicate value of EmpNo. An exception will be thrown as shown here:

mvc-exception

Pressing F5, the OnException method will be executed and the Error view will be displayed:

error-page

The above approach is good, but the limitation here is that it is specific to the controller and needs to be implemented for every controller.

In ASP.NET MVC 4 and 5 versions, we have been provided a mechanism of handling exceptions at global level so that we can instruct the controller to handle exceptions with no efforts. 

Handling Exceptions Globally using MVC 4 and 5 FilterConfig

When we create an MVC 4 or 5 Application using Visual Studio 2012 to 2013, we get the FilterConfig class in the App_Start folder as shown here:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

The class contains the RegisterGlobalFilters static method with GlobalFilterCollection as input parameter. This class contains all the global filters. Currently the HandleErrorAttribute is added in it. The HandleErrorAttribute is different than Application_Error because HandleErrorAttribute is used for managing exceptions during Controller execution in MVC, while the Application_Error occurs when the request is out of MVC because ControllerContext is closed here. The HandleErrorAttribute is applied on the MVC Controller class or in its action method to handle Exceptions thrown by Action methods. The RegisterGlobalFilters is called in the Global.asax asshown  below:

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

This handles all exceptions raised across all action methods in all controllers in the MVC application.

Lets see the implementation of Exception filter for our current application.

Step 1: Open Web.Config file of the application and add the following tag under <system.web> to manage the custom errors:

<customErrors mode="On"></customErrors>

Step 2: Remove (or comment out) the OnException method from the EmployeeInfoController class.

Step 3: In the EmployeeInfoController class add the following attribute:

[HandleError(ExceptionType = typeof(DbUpdateException), View = "Error")]
    public class EmployeeInfoController : Controller
    {


An Error filter is applied on the controller class with the Exception type as DbUpdateException and the View as Error.

Run the application and try to enter duplicate record in the EmployeeInfo table using duplicate value of the EmpNo. The code will crash at the throw ex in the catch block of the Create action method. Pressing F5, the Error page will be displayed:

error-page

We can add multiple HandleError attributes on the Controller (or on its actions methods) to handle exceptions. This approach will handle exceptions on Controller level.

Conclusion: We have various ways of handling exceptions in ASP.NET MVC. It is our responsibility as a developer to choose the most appropriate one for our requirements.

Download the entire source code of this article (Github)

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Mahesh Sabnis is a DotNetCurry author and a Microsoft MVP having over two decades of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions), and Front-end technologies like Angular and React. Follow him on twitter @maheshdotnet or connect with him on LinkedIn


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by Aditya on Tuesday, January 13, 2015 12:42 AM
Superb..... thanks a lot for such a good article
Comment posted by Lisa on Tuesday, January 13, 2015 3:10 AM
Mahesh I like your articles. Can you write more on Knockoutjs and Angularjs in ASP.NET Webforms
Comment posted by dhananjay kumar on Thursday, January 15, 2015 12:36 AM
Superb..... thanks a lot for such a good article.can to write something validation in mvc.
Comment posted by chandrashekhar Rai on Wednesday, February 11, 2015 4:52 AM
Hi Mahesh,
very nice post.
Can you do the same for empty mvc5 project for vs 2012
Comment posted by Asif on Tuesday, March 24, 2015 1:16 PM
Are you able to compile the code when you return ex in your catch block?

[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
    try
    {
        ctx.EmployeeInfoes.Add(Emp);
        ctx.SaveChanges();

        return RedirectToAction("Index");
    }
    catch(Exception ex)
    {
        throw ex;
    }
}
Comment posted by hgfhfg on Wednesday, March 25, 2015 8:08 AM
fghfgh
Comment posted by Asif on Wednesday, March 25, 2015 9:26 AM
Are you able to compile the code when you return ex in your catch block?

[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
    try
    {
        ctx.EmployeeInfoes.Add(Emp);
        ctx.SaveChanges();

        return RedirectToAction("Index");
    }
    catch(Exception ex)
    {
        throw ex;
    }
}
Comment posted by drilldriversq.com on Wednesday, April 1, 2015 11:14 PM
hi, how can i download this full your source code