Creating Custom Action Filters in ASP.NET MVC

Introduction

In ASP.NET MVC applications the controller consists of one or more methods known as actions or action methods. In certain cases you require that in addition to the code written in the action method, some extra processing be carried out before or after the action method execution. To accomplish this MVC offers what is known as Action Filter. If you have programmed in ASP.NET MVC before, chances are that you already used some in-built action filters. For example, the [OutputCache] and [Authorize] attributes provided by ASP.NET MVC are actually action filters. Additionally you can build your own action filters to fit a specific purpose. This article teaches you just that.

Types of Action Filters

If an action method has more than one action filter applied, the order in which they are executed is not fixed. This may not be desirable in all the situations. Consider, for example, a case where your custom action filter is doing some security checking and you wish to run it before any other action filter runs. To take care of such situations the ASP.NET MVC framework provides certain interfaces. Based on the interface your action filter implements its execution order is determined. To be specific, the following four types of action filters can be created based on the interface they implement.

  1. Authorization Filters : These filters are always run first before any other filters and they implement IAuthorizationFilter interface.
  2. Action Filters : Action filters run before and after the controller action method and implement IActionFilter interface.
  3. Result Filters : Result filters are executed before and after the view and implement IResultFilter interface.
  4. Exception Filters : These filters execute in the end and implement IExceptionFilter interface.

Thus action filters are executed in the order 1-2-3-4 and you can control where a specific custom filter goes with the help of corresponding interface.

Technically an action filter is a class that inherits from FilterAttribute base class and then implements required interfaces. Before we go ahead and create our own action filter here is what a skeleton code looks like :

public class MyActionFilterAttribute : FilterAttribute, IActionFilter
{
 ...
}
public class Home : Controller
{
   [MyActionFilter]
   public ActionResult Index() {...} 
}

To simplify your work ASP.NET MVC comes with a class - ActionFilterAttribute that already inherits from the FilterAttribute base class and implements IActionFilter and IResultFilter interfaces. So, as an alternative you can also inherit your class directly from ActionFilterAttribute base class and then override its methods.

Creating Your Own Action Filter

At a minimum a custom action filter class inherits from the FilterAttribute base class. Based on your requirements you may need to perform the following steps:

  1. Decide whether your custom action filter needs to have a specific order in the execution chain.
  2. Depending on the required order, implement IAuthorizationFilter or IActionFilter or IResultFilter or IExceptionFilter.
  3. If you are implementing IAuthorizationFilter interface then write implementation for OnAuthorization() method.
  4. If you are implementing IActionFilter interface then write implementation for OnActionExecuting() and OnActionExecuted() methods.
  5. If you are implementing IResultFilter interface then write implementation for OnResultExecuting() and OnResultExecuted() methods.
  6. If you are implementing from IExceptionFilter interface then write implementation for OnException() method.
  7. Decorate action methods with one or more action filters.

Sample Action Filters

In order to understand how action filters work you will create the following four action filters :

ValidateUserRoles

ASP.NET MVC comes with an inbuilt action filter - [Authorize] - that can be used for role based security. The [Authorize] attribute, however, expects a role name at development time. For example, here is a sample usage of [Authorize] attribute:

[Authorize(Roles="Administrator")]

But what if you don't know the role name at development time? What if the roles allowed to invoke an action method are coming from a database? In such cases you cannot use the [Authorize] attribute as shown above. To tackle this problem you will create a ValidateUserRoles custom action filter that will give you a chance to verify a currently logged in user against roles that are pulled from the database (though we won't write the actual database code here to keep things simple). Clearly ValidateUserRoles is an authorization filter and will implement IAuthorizationFilter interface.

TrackUserIP

At times you need to capture the IP address of the client invoking an action method (say for security, tracking or analytical reasons). The TrackUserIP action filter will do just that. The TrackUserIP is a normal action filter and hence will implement IActionFilter interface.

DisplayAds

A common scenario in web pages is to render advertisements. One way to achieve this is to include advertisement rendering logic in the web page itself. However, this approach may not be suitable in all the cases. The DisplayAds action filter appends advertisements when a result is processed. This way the view need not know anything about the advertisement display logic. They are emitted in the final output by the DisplayAds action filter. Since DisplayAds action filter works on the output of views it needs to implement IResultFilter interface.

NotifyException

The NotifyException action filter sends a notification to an email address whenever there is any error in an action method or view. You can use this action filter to notify the administrator or technical team about the exception so that corrective action can be taken if necessary. The NotifyException action filter is an exception action filter and hence will implement IExceptionFilter interface.

To begin developing these custom action filters, create a new ASP.NET MVC 3 web application. You can either implement Forms Authentication yourself or use the default mechanism. The following sections assume that you have Forms Authentication and membership in place with a role - Administrators.

Then create a folder named CustomFilters and add four class files to it viz. ValidateUserRoles.cs, TrackUserIP.cs, DisplayAds.cs and NotifyException.cs

ValidateUserRoles Action Filter

The following listing shows the ValidateUserRoles action filter :

public class ValidateUserRoles:FilterAttribute,IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        Debug.WriteLine("Inside OnAuthorization");
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            if (!Roles.IsUserInRole("Administrators"))
            {
                ViewResult result = new ViewResult();
                result.ViewName = "SecurityError";
                result.ViewBag.ErrorMessage = "You are not authorized to use this page. Please contact administrator!";
                filterContext.Result = result;
            }
        }
        else
        {
            ViewResult result = new ViewResult();
            result.ViewName = "SecurityError";
            result.ViewBag.ErrorMessage = "You are not authenticated. Please log-in and try again!";
            filterContext.Result = result;
        }
 
    }
}

As you can see, the ValidateUserRoles class inherits from the FilterAttribute base class and also implements the IAuthorizationFilter interface. The IAuthorizationFilter interface expects you to write implementation of the OnAuthorization() method.

The OnAuthorization() method receives a parameter of type AuthorizationContext that gives you access to the underlying controller and result. The code then checks whether the current request is authenticated or not. If the request is authenticated it further checks the user role. In the example above you have used the role name (Administrators) as a literal value but in a more real world scenario you can fetch it from some database or configuration file. If the user doesn't belong to the specified role we create a new ViewResult object based on the SecurityError view (you will create the views later), set the ErrorMessage member of the ViewBag and then set the Result property of the filterContext parameter. This way if the user doesn't belong to the Administrators role, an error message will be displayed on the screen. If the user is not yet authenticated we display an appropriate error message prompting him to log-in and try again.

TrackUserIP Action Filter

The TrackUserIP action filter inherits from the FilterAttribute base class and implements IActionFilter. The following listing shows the complete code of the TrackUserIP action filter.

public class TrackUserIP:FilterAttribute,IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Debug.WriteLine("Inside OnActionExecuting");
        string userIP = filterContext.HttpContext.Request.UserHostAddress;
        LogIP(filterContext.HttpContext.Request.Url.PathAndQuery,userIP,"Attempted");
    }
 
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        Debug.WriteLine("Inside OnActionExecuted");
        string userIP = filterContext.HttpContext.Request.UserHostAddress;
        LogIP(filterContext.HttpContext.Request.Url.PathAndQuery, userIP, "Completed");
    }
 
    private void LogIP(string url,string ip,string msg)
    {
        Debug.WriteLine(msg + " : " + url + "[" + ip + "] on " + DateTime.Now.ToString());
    }
 
}

The IActionFilter interface requires that you implement OnActionExecuting() and OnActionExecuted() methods. As you might have guessed these methods are executed pre and post the controller action under consideration. In both the methods we just log the IP address of the client to the Visual Studio Debug window. In a more realistic situation you will store it in some database. So the sequence of execution will be OnActionExecuting() - Action Method - OnActionExecuted().

DisplayAds Action Filter

The DisplayAds action filter is a result filter and implements the IResultFilter interface. The complete code of the DisplayAds action filter is given below:

public class DisplayAds:FilterAttribute,IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext filterContext)
    {
        Debug.WriteLine("Inside OnResultExecuting"); 
        filterContext.Controller.ViewBag.AdMarkup = GetAdMarkup();
    }
 
    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
        Debug.WriteLine("Inside OnResultExecuted"); 
        UpdateAdImpressions();
    }
 
    private string GetAdMarkup()
    {
        return "<hr />This is ad text.<hr />";
    }
 
    private void UpdateAdImpressions()
    {
        //write database code to increment
        //ad impressions here.
    }
}

The IResultFilter interface expects you to implement OnResultExecuting() and OnResultExecuted() methods. These methods are executed before and after the view is processed. The OnResultExecuting() method retrieves the ad markup based on some logic and sets a ViewBag member accordingly. This way AdMarkup member is available to the view before rendering the contents. The OnResultExecuted() method can be used to keep track of ad impressions. Note that GetAdMarkup() and UpdateAdImpressions() methods don't contain any significant logic in the example above. In a real world scenario you will have some database driven logic in these methods.

NotifyException Action Filter

The NotifyException action filter is an exception filter and hence implements the IExceptionFilter interface. The complete code of the NotifyException class is given below:

public class NotifyException:FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        Debug.WriteLine("Inside OnException"); 
 
        if (filterContext.Exception != null)
        {
            string msg = filterContext.Exception.Message;
            SmtpClient email = new SmtpClient();
            email.Send("admin@foo.com", "test@foo.com", "Error in MVC application", msg);
        }
    }
}

The IExceptionFilter interface requires that you implement the OnException() method. The OnException() method is called only if there is any exception during the execution of the action or result. The Exception property of the filterContext parameter gives you the Exception that was thrown. You can then send an automated email using the SmtpClient class.

Using Custom Action Filters

Now that your custom action filters are ready, it's time to use them in some controller. Add a new controller named HomeController and code the Index() action method as shown below:

public class HomeController : Controller
{
    [Authorize]
    [ValidateUserRoles]
    [TrackUserIP]
    [DisplayAds]
    [NotifyException]
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome!";
        return View();
            
    }
}

Notice how the Index() method is decorated with action filter attributes. The Index() method simply sets a member of ViewBag (Message) and renders the Index view. The Index view is shown below:

<html>
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
       <h1><%= ViewBag.Message %></h1>
    </div>
    <%= (ViewBag.AdMarkup == null ? "" : ViewBag.AdMarkup)%>
</body>
</html>

Recollect that AdMarkup member is being set via the DisplayAds action filter.

Before you run the application you need one more view - SecurityError. The markup of the SecurityError view is shown below :

<html>
<head runat="server">
    <title>SecurityError</title>
</head>
<body>
    <div>
        <strong><%= ViewBag.ErrorMessage %></strong>
        <%= Html.ActionLink("Login","Login","Membership") %>
    </div>
</body>
</html>

The SecurityError view simply displays the ErrorMessage as set by the ValidateUserRoles action filter. A login link is also rendered so that the user can navigate to the login page. (You will find the Membership controller in the code download. If you are using some other mechanism of authenticating users you should change the ActionLink call accordingly.)

Now run the web application and log-in to the system. If the user is not an Administrator you should get an error message like this :

Error: User not an Administrator
Figure 1: Error: User not an Administrator

If the user belongs to the Administrators role you will be able to view the Index view as shown below :

View the Index
Figure 2: View the Index

Notice how the advertisement markup as set by the DisplayAds action filter is displayed. If you see a Visual Studio Output window, it should resemble as shown below :

Visual Studio Window
Figure 3: Visual Studio Window

Notice the sequence of various Debug.WriteLine() statements that are outputted.

Summary

In ASP.NET MVC applications, in addition to the code written in the action methods, you may want some extra pre or post processing be carried out. ASP.NET MVC allows you to do this with the help of Action Filters. An action filter is a class that inherits from the FilterAttribute base class. Depending on your need you can implement IAuthorizationFilter, IActionFilter, IResultFilter or IExceptionFilter interfaces to make your filter an authorization filter, action filter, result filter or exception filter respectively. These interfaces decide the order in which the action filters are executed.



About the Author

Bipin Joshi

Bipin Joshi is a blogger and writes about apparently unrelated topics - Yoga & technology! A former Software Consultant by profession, Bipin has been programming since 1995 and has been working with the .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. He was a well known technology author, trainer and an active member of Microsoft developer community before he decided to take a backseat from the mainstream IT circle and dedicate himself completely to spiritual path. Having embraced Yoga way of life he now codes for fun and writes on his blogs. He can also be reached there.

Related Articles

Comments

  • Nike Zephyr Max 1 FB liberating, have a eager color grain, the unheard of shoes

    Posted by Geozyoceada on 04/23/2013 07:00pm

    In the summer in a glass backing bowels the chilling sprite seems to be a godlike choice, but if the sprite "feet"? Inclination also give you a lapse, get a refreshing! This summer, Nike and Sprite [url=http://markwarren.org.uk/property-waet.cfm]air max 90 uk[/url] and his sneakers to a blend of exemplary snow spread of non-professional, unsullied and indecent color scheme in the definitive Nike Feeling Max 1 shoes reveal a drinks chill scent.[url=http://markwarren.org.uk/property-waet.cfm]air max 90[/url] Summer is the time to hand-pick a clean shoe, shoes should be a good choice. Qualifying series Nike Freshen Max HomeTurf borough recently definitely comes up, this series in the immortal Breath Max shoes to London, Paris and Milan the three paid glorification to the iconic see of Europe, combined with the characteristics of the three cities, Like Max 1 HYP,Air Max 90 HYP,Connected Max 1 and shoes such as Air Max 95, combined [url=http://markwarren.org.uk/goodbuy.cfm]nike free run[/url] with the Hyperfuse, as marvellously as a heterogeneity of materials, such as suede, Whether you hankering functioning or retro-everything.

    Reply
  • Excellent Article

    Posted by Jithesh on 03/25/2013 05:57am

    If we can download code. It would be more helpful.

    Reply
  • Nice one there

    Posted by Slalaleasyday on 03/15/2013 08:32pm

    Nice Post. ---------- I love http://youtube.com

    Reply
  • La plupart de bienvenue substandard les talons hauts etoiles: Christian Louboutin Jordan

    Posted by Vetriatszy on 03/14/2013 02:27pm

    Detroit inventions Do you care about precisely Selena Gomez wore at the ex usefulness heading towards Grove? Selena dressed in an attractive bridal flowers peak which may be cinched in at the stomach along with a wide lace top princess neck line. Selena quite possibly dressed in lanky tight pants or skirts and therefore dunkle Learn More cancelled toe of the feet running shoes in order to complete this appear. an alternative investigate that is great for recreational outings is to be found at Nordstrom. Nordstrom goes inspirations to the have a look; A split fine mesh but also silk tshirt just by group rules of only costs $88.00 along created 'Aphrodite' hat highest that includes shoelace and read-interweave crocheted refined in your neck-line that by Free travelers ($98.00). regarding price patrons, Abercrombie and Fitch has an attractive flower rainwater tank for sale needed for $30.00; marvelous to put on as layered be on the lookout or even without help. A tank top that is nearly the same as Selena's clothing is known as the built up cami, made inorganic cotton (plus fully provided alongside egypt)

    Reply
  • Abercrombie and Fitch britannique boutique en ligne, nous offre les modes les together with courants Abercrombie spew into common cogitate about les femmes et les hommes the

    Posted by Vetriatszy on 03/14/2013 06:21am

    Abercrombie along with Fitch Outletabercrombie fitch great deal via than, we both received your own chance the bebercrombie Fitch. There are a'substantial amount'of designer handbags of countless excellent dimensions with various forms. I were not able to change their attention. it couldn't be me! i had produced never ever dreamed that I could very well be this kind of pretty and / or balanced the day. we had been too surprised to state that nearly any password, Neither have done my pal Linda. It wasn't till that time could we understand the appeal found in a we provided the wallet we yearned and was far more straight away towards the university. you will see that inclinations safeguard at upgrading, however,though leather coats, coats and hooded sweatshirts make mostly been in fashion since the standing of these shirts, posses in no way ended up washed out. A sasgle can be fairly up-to-date as well modern layers applications. you will find loads and many models, Which are offering to you multiple varieties not to mention kinds short coat jackets, except between americans models, Abercrombie is the particular and best-selling label of united states of america, containing been charging money for firmly skilled and therefore high quality patterns involved with short coat jackets. many, what people frequent refridgerator rooms, the particular Abercrombie offers individual you could try here designs of jerkin, that will make them, lookup well-known and as well,as well as the hot. nothing at all can be a little more chic additionally cutting-edge in contrast Abercrombie cover. rrndividuals are in have pleasure in with the reliable along with patterns that's Abercrombie yields from this is clothing. inside a this particular wear these model improves own -rely on about fellas, For which they go on her or his need for the buying ones coats. some sort of hooded sweatshirts, Which are fashioned by Abercrombie, have always been higher than average funky then nevertheless,having said that in vogue. merely by putting on a hoodie as to Abercrombie, You are in fact going to include production to your overall identity. whether you have almost matters somewhere around yours health or the health of your child, it is wise to meet with a physician maybe other kinds of healthcare professional. don't hesitate to look at the online privacy policy in addition regards to Use well before employing this site. your call time site exhibits transaction to be able to restricted by your relation to Use

    Reply
  • Nice Article

    Posted by sampath on 03/03/2013 03:46am

    It's a clean and clear explanation. Keep it up your good work.

    Reply
  • RjrSxU wJ PW LKt FkMC pn

    Posted by cMECTRJEcr on 02/19/2013 07:25pm

    buy tramadol online tramadol medication overdose - generic tramadol no prescription overnight

    Reply
  • where is the download link ?

    Posted by phillip on 09/21/2012 08:48am

    please , could you send me the code project sample ?

    Reply
  • code download

    Posted by paul on 08/30/2012 02:50am

    code download????

    Reply
  • software/web developper

    Posted by El bayamés on 08/03/2012 08:12am

    me again... you said "You will find the Membership controller in the code download." Where is the code download? Can you send it to me please?

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds