Home > .Net, Articles, c#, Code samples > ActionFilters in MVC

ActionFilters in MVC

October 20th, 2009 Leave a comment Go to comments

I’ve been working on two fairly large MVC-projects lately. ImagerGallery.Net and a webshop-application suitably named BeaverShop. While working on those projects I’ve realized that I just love being able to use ActionFilters in MVC. Basically, they are attributes that you append to action-methods. They can be used to validate input, parse data into more suitable structures, check security and lots more.

One of my most used filters in both ImagerGallery and BeaverShop is one I named PagingAttribute which I thought I should show to you today.

Any ActionFilter need to inherit the ActionFilterAttribute and implement at least one of the following methods: OnActionExecuting, OnActionExecuted, OnResultExecuting or OnResultExecuted. They are all called during different stages of the execution of an action-method and can be used for various things. The one I’ll be using is OnActionExecuting since it is executed before the action so that I can pass extra arguments to the action.

The code is quite easy to understand. There is only one property to be set (except for the default property Order which is defined in ActionFilterAttribute) which is which field to be parsed. I check if the field is null or empty, if not ten I use a regular expression to see check if the selected field ends with “page” and a numerical value. The numerical value is then returned as a argument for the action called “pageNo”. This value is defaulted to 1 to make sure that we always get a number for our page (and not specifying anything should mean the first page). In my case I also want the field to be modified so it doesn’t contain the “page” part but that might not be suitable for everyone. If not, then you can easily remove that part by commenting the line looking like this: filterContext.ActionParameters[Field] = id;

using System;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;

namespace BeaverShopMvc.Attributes
{
    /// <summary>
    /// An ActionFilter to parse a page number from a field value
    /// </summary>
    public class PagingAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// The name of the field to parse
        /// </summary>
        public string Field { get; set; }

        // A compiled regular expression to speed things up
        private static Regex _pageRegex = new Regex("page(?<PageNo>\\d+)$", RegexOptions.CultureInvariant | RegexOptions.Compiled);

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            string id = filterContext.ActionParameters[Field] as string;
            Int32 pageNo = 1;

            // We never need an ending / so remove it
            id = id.TrimEnd('/');

            // Check so that the field isn't empty and while at it also that it
            // contains "page"
            if (!string.IsNullOrEmpty(id) && id.ToLowerInvariant().Contains("page"))
            {
                Match match = _pageRegex.Match(id);
                if (match.Success)
                {
                    pageNo = Convert.ToInt32(match.Groups["PageNo"].Value);
                    if (id.Contains("/"))
                        id = id.Substring(0, id.LastIndexOf('/'));
                    else
                        id = string.Empty;
                }
            }

            filterContext.ActionParameters["pageNo"] = pageNo;
            // The line below replaces the old field value with a
            // new one without the "page" part
            filterContext.ActionParameters[Field] = id;

            base.OnActionExecuting(filterContext);
        }
    }
}

Using the attribute is really simple and the great thing about this is that it is easily reusable on any actions you need it to. Below is a little sample of it in action.

        [Paging(Field = "id")]
        public ActionResult ListProducts(string id, Int32 pageNo)
        {
            return View();
        }

I have a few more filters that I really like as well (AkismetValidatorAttribute for example) that I might share some other day. I’m still learning a lot about working with MVC and will keep you posted with what other interesting things I can find.

  1. No comments yet.
  1. No trackbacks yet.