Exception Filter - By Narendra Shrestha
It’s already been said before that exception filters
comes to life only when an exception is thrown from other filters, action
methods and action results. Like authorization filter, this filter also has its
custom implementation and default implementation too. We don’t have to worry a
lot when we are implementing our own exception filters because there is
virtually no security risk as in case of authorization filter.
When implementing custom exception filter, we
need to implement interface “IExceptionFilter” in our custom class. The skeletal code for
this interface is as listed below
using System;
namespace
System.Web.Mvc
{
// Summary:
// Defines the methods that are required for
an exception filter.
public interface IExceptionFilter
{
// Summary:
// Called when an exception occurs.
//
//
Parameters:
// filterContext:
// The filter context.
void
OnException(ExceptionContext filterContext);
}
}
Listing 1:- “IExceptionFilter” interface skeletal code
When exception arises, “OnException” method in our
custom class is invoked. This method accepts input parameter of type “ExceptionContext”. “ExceptionContext” is derived from class
controller “ControllerContext”. As a result, we get access to various properties such as route data, http
context, requests, controller specific properties etc.
Apart from the derived properties, “ExceptionContext” has its own useful properties such as:-
·
“Result” of type “ActionResult” which is the result
of the action method
·
“ExceptionHandled” of type “bool” indicates if
another filter has handled the exception
·
“Exception” of type “Exception” which is the
unhandled exception that was thrown
Our action method may include several exception filters. If error arises on
behalf of any exception filter, we set “ExceptionHandled” property to true. Based on that value, we will prevent the re-handling of
the error in other exception filters. If exception is handled by none, then
ASP.NET framework will display the unpopular error page. “Result” property is used by exception filter to instruct MVC framework
accordingly. Since “Result” property is of type “ActionResult”, we can instruct MVC framework in many ways
such as rendering a view, redirecting to route or action etc. However, setting
“Result” property to null simply means we have cancelled
the request.
To explore exception filter, let us create
our own exception filter class “MyExceptionAttribute” within “infrastructure” folder. This class implements the interface “IExceptionFilter”. Still I
haven’t revealed a valuable bit of information. In order to qualify as a
filter, any custom class should be derived from class “FilterAttribute”. “FilterAttribute” implements “IMvcFilter” which grants it an
identity of the filter. “FilterAttribute” is derived from class “Attribute” making the class eligible enough to be used as .net attribute. We didn’t
do so in authorization filter because we weren’t implementing “IAuthorizationFilter”. Instead we
derived our authorization filter from class “AuthorizeAttribute” which already takes
care of all these necessary steps.
The code for the “MyExceptionAttribute” class is listed
as below:-
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
using
System.Web.Mvc;
namespace
Filters.Infrastructure
{
public class MyExceptionAttribute:FilterAttribute, IExceptionFilter
{
#region IExceptionFilter Members
public void OnException(ExceptionContext
filterContext)
{
if
(!filterContext.ExceptionHandled && filterContext.Exception is UnAthorizedException)
{
filterContext.Result = new ViewResult {
ViewName = "UnAuthorized" };
filterContext.ExceptionHandled
= true;
}
}
#endregion
}
}
Listing 2:- “MyExceptionAttribute” class
Inside “OnException” method, we checked if the exception has been handled by other existing
exception filters. If the exception happens to be of type “UnAthorizedException”, then the result
is set to be of “ViewResult” type. The name of the view is specified as “UnAuthorized” which is an
existing view in the shared folder (refer filter part 1). “ExceptionHandled” property is set to true
so that other exception filter can know whether the particular exception has
been handled by other exception filters. It is most likely to be useful in any
action implementing multiple exception filters. For example let us assume that an exception
was thrown and has already been handled by an exception filter. When another
exception filter that follows the first one refers to this property, the value
will be already set to true. We are saved from overload i.e. unnecessary
re-handling of the same error.
Take a close notice of class “UnAthorizedException” which happens
to be a custom exception type. We place this custom exception type within
“infrastructure” folder along with other custom filter codes. The following
list shows the code for “UnAthorizedException”. Frankly, nothing has been done within this exception type rather than
calling the base class methods. Still this fulfills our desire to own a custom
exception type. Hence, we are planning to throw this exception in case of
unauthorized access.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Filters.Infrastructure
{
public class UnAthorizedException:Exception
{
public
UnAthorizedException()
{
}
public
UnAthorizedException(string message):base(message)
{
}
public
UnAthorizedException(string message, Exception innerException)
: base(message,
innerException)
{
}
}
}
Listing 3:- “UnAthorizedException” class
The custom authorization feature should be cross checked or disabled before
proceeding with example below. Since Authorization filters run prior to others,
“FormsAuthentication.Authenticate” may behave oddly to your surprise. You will be reusing this authentication
method again as mentioned below in the code. Below are the changes which are made
within the “Home” controller.
[MyException]
public string Vault()
{
//if
(!Roles.RoleExists("admin"))
//{
// Roles.CreateRole("admin");
// Roles.AddUsersToRole(new[] {
"name" }, "admin");
//}
//FormsAuthentication.Authenticate("name",
"name");
//FormsAuthentication.SetAuthCookie("name",
false);
if (User.IsInRole("admin") && User.Identity.IsAuthenticated)
{
return "Welcome to the dummy vault";
}
else
{
throw new UnAthorizedException();
}
}
Listing 4:-“Vault” action in “Home”
controller
Take a closer look; the exception filter attribute
“[MyException]” is applied to our “Vault” action. Whenever, an exception is thrown
from our action method, the custom exception filter will be triggered. In case
if the error is of custom exception “UnAthorizedException” type, exception filter will arrange suitable result.
Run the project, enter URL “/Home/Vault”, and
you can see the following output. Although, role “admin” already exists (refer
filter part 1), still we aren’t authenticated yet. As a result, error will be
thrown for failed authentication and our custom exception filter will be
triggered.
Figure 1:- When “UnAthorizedException” is thrown is
thrown by custom exception filter
Uncomment the code in listing 4. Once we run
the project and enter URL “/Home/Vault”, we will see the following output.
Figure 2:-When user is
authorized, no exception will be generated by custom exception filter
Default Exception Filter
It’s a real fun to dig deep inside various nooks and corners of MVC and
explore its functionality. It magnifies the scenarios which happen behind the
scenes. Still we can’t count out the default functionality. One reason to
embrace the default functionality is because we know that it’s strongly tested.
Moreover, it has promising factors summing up for strong reliability. We can
replicate everything in default implementation which we already achieved in the
custom. Default implementation requires less effort i.e. less coding.
The default implementation of exception filter in MVC is “HandleErrorAttribute” (refer table 1 in Filter Part 1). This filter attribute
implements the interface “IExceptionFilter”. It is also derived
from “FilterAttribute”(necessary to be
recognized as filter and to be readily be used as an attribute)
Like other filters, “HandleErrorAttribute” has its own properties as following:-
·
“ExceptionType” of type “Type” indicating the
exception typed to be handled. Its default value is “Exception”
·
“View” of type “string” indicates view to render when exception is
thrown. The default view taken from the “Web.config” file.
·
“Master” of type “string” is the layout to be used when rendering an
exception view. When we don’t specify any layout, the default layout stated in
“_ViewStart.cshtml” is chosen.
For default implementation, we are repeating the same thing that we already
did in the custom implementation. We disabled all the codes related to custom
exception filter from the “home” controller. The following code list the
changes we made to “Vault” action method inside the “home” controller.
[HandleError(ExceptionType
= typeof(UnAthorizedException),
View = "UnAuthorized")]
public string Vault()
{
//if
(!Roles.RoleExists("admin"))
//{
// Roles.CreateRole("admin");
// Roles.AddUsersToRole(new[] {
"name" }, "admin");
//}
//FormsAuthentication.Authenticate("name",
"name");
//FormsAuthentication.SetAuthCookie("name",
false);
if
(User.IsInRole("admin") &&
User.Identity.IsAuthenticated)
{
return "Welcome to the dummy vault";
}
else
{
throw new UnAthorizedException();
}
}
Listing 5:- changes made to “Vault” action in “Home” controller for default
exception filter
The default exception filter attribute “HandleError” is applied to the “Vault” action. As a named parameter, “ExceptionType” is set to be of type “UnAthorizedException”, and view in case of exception is set to “UnAuthorized”.
Also, we need to make little changes inside “Web.config” file. Since “HandleError” works only when custom error mode is turned
on, in “Web.config” file we make following changes:-
<customErrors mode="On" defaultRedirect="/Views/Shared/Error.cshmtl"/>
Listing 6:-Changes to “Web.config” file to turn on “HandleError” attribute
If we run our
project at this point, we can see the following output generated
Figure 3:- When “UnAthorizedException” is thrown is thrown by default exception filter
We aren’t authorized yet. As a result, exception of type “UnAthorizedException” is thrown, and we will
be taken to this view as specified within the named parameter “View” for the “HandleErrorAttribute” filter attribute. When
we uncomment the code in listing 5 and run the solution once again, we can see
the following output.
Figure 4:-When user is
authorized, no exception will be generated by default exception filter
Hence, we replicated same functionality in
both default and custom exception filter. However, from the viewpoint of
testability, the default one is much easier to mock and unit test. While
working with custom one, we will need to mock many of HTTP context methods and
properties. It’s not that hard to mock these classes, but still it depends on
our choice. If you think you are better off without custom implementation, you
may be right but still when you want your own custom behavior, the door is
always open.
ASP.NET MVC Training | MVC Online Training | MVC Training | ASP.NET MVC Training in Chennai | ASP.NET MVC 6 Training | Dot Net Training in Chennai
ReplyDelete.Net MVC Training | ASP.NET MVC Online Training | C# MVC Training | ASP.NET MVC Training in Chennai | Online ASP.NET MVC 6 Training | Dot Net Training in Chennai