Building an ActionFilter - BeforeFilter for ASP .Net MVC, Part 3

The last feature that I want to add to my BeforeFilter is an exclusion list that specifies controller actions for which not to execute the filter methods. Assume that you have Edit/Create/Display views; the Edit and Create views could – for example - require additional data to render drop down lists. If we populate this data with a before filter we should have the ability to exclude the Display view from the filter where this additional data is not necessary.

Attribute parameters can only be constant expressions so we have that restriction to contend with. The usage should be friendly and easy to use – a little syntactic sugar doesn’t hurt. I was contemplating something similar to the snippet below:

    [BeforeFilter("Initialize", Except = new [] {"Index", "Details"} )]
    public class ItemController : Controller
    {
        ...
    }

This looks pretty straight forward and the implementation should not be too difficult.

How are we going to know the action that is about to be executed? The OnActionExecuting method is passed an ActionExecutingContext. It contains an ActionDescriptor object that has various interesting properties including the ActionName.

Naturally we begin with a test. Our test setup will changes slightly so that we can mock the ActionDescriptor and create the context with the mocked out version. The test will include a setup for the ActionName property and verify that the filter methods are not invoked for the actions specified in our list. The setup and the test code is below:

    [SetUp]
    public void Before()
    {
        controller = new Mock<TestController>();
        descriptor = new Mock<ActionDescriptor>();
        context = new ActionExecutingContext
                        {
                            Controller = controller.Object, 
                            ActionDescriptor = descriptor.Object
                        };
    }

    [Test]
    public void should_not_call_specified_controller_method_given_an_action_is_an_exception()
    {
        descriptor.SetupGet(x => x.ActionName).Returns("Display");
        var attribute = new BeforeFilterAttribute("initialize", "logaction")
                            {
                                Except = new [] {"Display"}
                            };

        attribute.OnActionExecuting(context);

        controller.Verify(x => x.initialize(), Times.Never());
        controller.Verify(x => x.logaction(), Times.Never());
    }

The implementation for OnActionExecuting changes very little, we simply check if the ActionName is on the exception list before invoking the filter methods:

    if(!Except.Contains(filterContext.ActionDescriptor.ActionName))
        controllerMethod.Invoke((object)controller, new object[] { });

And that’s that, we now have a fairly complete BeforeFilterAttribute we can use to keep controllers clean.


Building an ActionFilter - BeforeFilter for ASP .Net MVC, Part 2

I’ve decided to add more features to the before filter I’ve build in the previous post. I need a way to specify a few methods I’d like to execute before the controller actions. I can do that now by specifying a number of BeforeFilter attributes but that looks a little silly. What I want is the ability to do something like this:

    [BeforeFilter("InitializeCategories","InitializeProvinces")]

This should be fairly easy to accomplish. We should probably start with a test. I’ve added a logaction method to the test controller so we can assert it was called. Here is the test:

    [Test]
    public void should_call_all_specified_controller_methods_given_they_exist()
    {
        controller.Setup(x => x.initialize());
        controller.Setup(x => x.logaction());
        var attribute = new BeforeFilterAttribute("initialize", "logaction");

        attribute.OnActionExecuting(context);

        controller.VerifyAll();
    }

To make this pass we change our implementation slightly. The method names now become a collection we need to iterate over and invoke the method on the controller if found; if not, we throw and exception as before. I've changed the exception type to an InvalidOperationException.

    public BeforeFilterAttribute(string methodName) : this(new[] { methodName })
    {
    }
        
    public BeforeFilterAttribute(params string[] methods)
    {
        this.methods = new List<string>(methods);
    }
        
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var controller = filterContext.Controller;
        foreach (var method in methods)
        {
            ...
        }

        base.OnActionExecuting(filterContext);
    }

This makes the test pass and now we have a BeforeFilter that’s a little more useful and friendly.

I would like to add one more feature to my BeforeFilter and that is an exception list. In other words, I would like a way to specify controller actions for which to NOT execute the methods. That way I have the ability to apply the BeforeFilter to the controller itself instead if the individual action and still retained fine grained control over the before methods that execute for a given action. I will leave that for a separate post.


Building an ActionFilter: BeforeFilter for ASP .Net MVC2

MVC2 has a nice feature called filters. They let you keep your controllers clean and factor out common code. This looks like it works particularly well for cross cutting concerns like security, logging, caching, etc. I’ve used in in one instance when I needed to populate the view bag with some common reference data used on the view to render a drop down list. With some lines omitted for brevity code for the controller looked something like this:

    [HandleError]
    public class ItemController : Controller
    {
        public ActionResult Edit()
        {
            ViewData["categories"] = repository.FindAll();

            return View();
        }
        
        public ActionResult Create()
        {
            ViewData["categories"] = repository.FindAll();

            return View();
        }
    }

We can quickly extract a method for the common code and call it InitializeCategories:

    private void InitializeCategories()
    {
        ViewData["categories"] = repository.FindAll();
    }

So you do this for a couple of controllers and you start to wonder if there is a more generic solution to this. We could try to extract a base class but that may not be suitable to all controllers or it could lead to some unpleasant inheritance hierarchy. This is when action filters come to mind. What if we could declaratively specify some method to execute before each controller action? We would like to end up with code similar to this:

    [HandleError]
    public class ItemController : Controller
    {
        [BeforeFilter("InitializeCategories")]
        public ActionResult Edit()
        {
            return View();
        }

        [BeforeFilter("InitializeCategories")]
        public ActionResult Create()
        {
            return View();
        }

        public void InitializeCategories()
        {
            ViewData["categories"] = repository.FindAll();
        }
    }

Writing an ActionFilter to handle this is relatively easy. There are a few types of filters available already, but for our purpose we can simply subclass ActionFilterAttribute and override the OnActionExecuting method. This method is called before out controller action executes. The method will be passed an ActionExecutingContext parameter which contains a variety of interesting information about the execution context including the controller instance. We can start by writing a test for our attribute. Lets say that we want to assert that a method on the controller is called if it exists. We make that pass and we write a second tests that asserts we throw a meaningful exception if the specified method does not exists. The tests looks like this:

    [TestFixture]
    public class A_BeforeFilterAttribute
    {
        private Mock<TestController> controller;
        private ActionExecutingContext filterContext;

        [SetUp]
        public void Before()
        {
            controller = new Mock<TestController>();
            filterContext = new ActionExecutingContext { Controller = controller.Object };
        }

        [Test]
        public void should_call_the_specified_controller_method_given_it_exists()
        {
            controller.Setup(x => x.initialize());
            var attribute = new BeforeFilterAttribute("initialize");

            attribute.OnActionExecuting(filterContext);

            controller.VerifyAll();
        }
        
        [Test]
        public void should_throw_invalid_method_exception_given_it_doesnt_exist()
        {
            var attribute = new BeforeFilterAttribute("nosuchmethod");

            Assert.Throws<Exception>(() => attribute.OnActionExecuting(filterContext));

            controller.VerifyAll();
        }

        public class TestController : Controller
        {
            public virtual void initialize()
            {
            }
        }
    }

I created a test controller so that I can set up an expectation that its method will be called. The mocking framework I used here is Moq. The implementation that makes the tests pass is below:

    public class BeforeFilterAttribute : ActionFilterAttribute
    {
        private readonly string methodName;

        public BeforeFilterAttribute(string methodName)
        {
            this.methodName = methodName;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var controller = filterContext.Controller;
            var method = controller.GetType().GetMethods().Where(x => x.Name.Equals(methodName)).FirstOrDefault();
            if (method == null)
            {
                throw new Exception(string.Format("The method {0} could not be found on {1}.", methodName, controller.GetType().FullName));
            }
            
            method.Invoke((object) controller, new object[] {});

            base.OnActionExecuting(filterContext);
        }
    }

Kind of a lengthy posts for such short code. This can be expanded a little so that we can specify a list of methods to be called, but I haven’t needed that yet and it’s all about providing value to the customer. That could maybe look something like this:

        [BeforeFilter("InitializeCategories","InitializeProvinces")]
        public ActionResult Edit()
        {
            return View();
        }

We can accomplish this by creating an overloaded constructor for the BeforeFilterAttribute:

        public BeforeFilterAttribute(params string[] methodName)
        {
        }

That’s it for now folks, if you decide to implement the overload please share!


Mapping inheritance hierarchies with Fluent NHibernate

A few days ago I briefly spiked mapping inheritance hierarchies with Fluent NHibernate. The result was so compelling I just have to post about it.

Based on our model we decided to go with class table inheritance. There is a brief discussion of the three well known mapping strategies in NHibernate in Action. What it boils down to is the differences in the classes. If they mostly differ by behavior class table inheritance is recommended, if the differ mostly by data than go with concrete table inheritance. Most of our differences are in behavior so we chose the former.

I used the classic sports player mode for the spike – an abstract Player class other player subclass, like a Base ballplayer for instance. I omitted model behavior from the spike since I focused on the mapping issue. The model looks like this:

    public abstract class Player
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual int Age { get; set; }
    }

    public class BaseballPlayer : Player
    {
        public virtual double BattingAverage { get; set; }
    }

This can be mapped manually, however is very tedious code that adds little business value to our customer. Writing this code by hand would also require a fairly significant investment in infrastructure. Instead we can map using Fluent NHibernate to it, like this:

    public class PlayerClassMap : ClassMap<Player>
    {
        public PlayerClassMap()
        {
            Id(x => x.Id);
            Map(x => x.Name);
            Map(x => x.Age);
        }
    }
    
    public class BaseballPlayerClassMap : SubclassMap<BaseballPlayer>
    {
        public BaseballPlayerClassMap()
        {
            Map(x => x.BattingAverage);
        }
    }

Believe it or not this all that is required to map the inheritance hierarchy above. Testing the mappings is also trivial using Fluent NHibernate’s PersitenceSpecification<T>. Here’s what the test code looks like:

    [TestFixture]
    public class BaseballPlayerClassMapTest : DatabaseTest
    {
        [Test]
        public void Should_do_something()
        {
            new PersistenceSpecification<BaseballPlayer>(session)
                .CheckProperty(x => x.Name, "Joe")
                .CheckProperty(x => x.Age, 23)
                .CheckProperty(x => x.BattingAverage, 0.99)
                .VerifyTheMappings();
        }
    }

This will create a BaseballPlayer, save it to the database, load from the database and verify all the mappings. If we look at the SQL statements generated we something like this:

INSERT INTO "Player" (Name, Age) VALUES (@p0, @p1); select last_insert_rowid();@p0 = 'Joe', @p1 = 23
INSERT INTO "BaseballPlayer" (BattingAverage, Player_id) VALUES (@p0, @p1);@p0 = 0.99, @p1 = 1
SELECT baseballpl0_.Player_id as Id9_0_, baseballpl0_1_.Name as Name9_0_, baseballpl0_1_.Age as Age9_0_, baseballpl0_.BattingAverage as BattingA2_10_0_ FROM "BaseballPlayer" baseballpl0_ inner join "Player" baseballpl0_1_ on baseballpl0_.Player_id=baseballpl0_1_.Id WHERE baseballpl0_.Player_id=@p0;@p0 = 1

The table structure NHibernate will generate is below.

image

Our test fixtures subclass a DatabaseTest class which constructs the session and generates the database schema from our model. We use SQLite for in-memory testing which makes out integration tests pretty fast. Here’s the code for the base class.

 

    public class DatabaseTest
    {
        private ISessionFactory sessionFactory;
        protected ISession session;
        private readonly FluentConfiguration configuration;
        private readonly Configuration config;

        public DatabaseTest()
        {
            config = new Configuration();
            configuration = Fluently.Configure(config)
                .Database(SQLiteConfiguration.Standard.InMemory().ShowSql())
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<HibernateSessionFactoryBuilder>());
        }

        [SetUp]
        public void Setup()
        {
            sessionFactory = GetSessionfactory();
            session = sessionFactory.OpenSession();
            BuildSchema();
        }

        [TearDown]
        public void TearDown()
        {
            session.Close();
            session.Dispose();
        }

        private void BuildSchema()
        {
            var export = new SchemaExport(config);
            export.Execute(false, true, false, session.Connection, null);
        }  

        private ISessionFactory GetSessionfactory()
        {
            return configuration.BuildSessionFactory();
        }
    }

This one could maybe use some cleanup but that’s all we need to do to map our model to the database. We can now focus on delivering business value and not spend too much time on writing mappers and other infrastructure code.


ASP.NET MVC basic validation with DataAnnotations

I am currently working on an MVC 2 project and we need basic validation for our models. An easy way to accomplish this is to use the attributes in the System.ComponetModel.DataAnnotations namespace. This works out of the box with no additional dependecies. For basic model validation you end up with something like this:

    public class LoginModel
    {
        [Required(AllowEmptyStrings = false, ErrorMessage = "Email address is required"),
         RegularExpression("@"^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*@(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4})$"", ErrorMessage = "Email address is invalid.")]
        public string EmailAddress { get; set; }

        public string Password { get; set; }
        public bool RemeberMe { get; set; }
    }

It looks a little clunky if you have a lot of attributes decorating one property, but for us it’s the simplest thing that works for now. Now we need a way to test this. My first instinct was to call Validator.TryValidate() on my model and get back the list of broken validation rules. To do this we need to first construct a validation context. The first tests looks like this:

        [Test]
        public void should_validate_given_a_model_with_a_missing_email_address()
        {
            var model = new LoginModel {EmailAddress = "", Password = "password", RemeberMe = false };
            
            var errors = ValidateModel(model);

            Assert.That(1.Equals(errors.Count()));
            Assert.IsNotNull(errors.Where(x => x.ErrorMessage.Contains("Email address is required")));
        }

        private IEnumerable<ValidationResult> ValidateModel(LoginModel model)
        {
            var results = new List<ValidationResult>();
            var context = new ValidationContext(model, null, null);
            Validator.TryValidateObject(model, context, results, true);

            return results;
        }

We needed to validate a few different models so we extracted the ValidateModel method into a base class, ValidationTestBase. The ValidateModel method is made generic so it can operate on any given model. The base class looks like this:

    public class ValidationTestBase
    {
        protected IEnumerable<ValidationResult> ValidateModel<T>(T model)
        {
            var results = new List<ValidationResult>();
            var context = new ValidationContext(model, null, null);
            Validator.TryValidateObject(model, context, results, true);

            return results;
        }
    }

In practice this works pretty well, and having this area well covered ensures no validation issues sneak up on us. You can easily implement a custom validator if you need something that is not provided out of the box. We had some debates around whether we should do more complex validations the same way or not. And easy example that comes to mind is check the database to determine if a user name is already taken. We decided that is better left to a service layer, and rely on the attributes only for basic data validation.

There is an equivalent open source solution to the DataAnnotations namespace – Castle.Components.Validator. The functionality provided is largely equivalent, although we didn’t explore it in detail. In a future post I will cover how to link the DataAnnotations to client side validation.


Search

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010