2.5.2010

IJoinedFilter Part 3: IFilterPriority

Note: This article is a continuation of the series on IJoinedFilter:

  1. IJoinedFilter
  2. AutoMapFilter meet IJoinedFilter

In-lining mapping and injection aspects – yuck!

After implementing several aspects of controller actions as compos-able filters, it became apparent that controlling the order would be import. One of the latest additions is a filter to build up a view model property with data aspects. An example would be a select list for states on a person edit view. Normally, the states would be fetched and set on the model in the controller action:

  public class PriorityController : Controller
  {
    public ActionResult Injected()
    {
      var person = new Person
                   {
                    Name = "John Doe",
                    BirthDate = new DateTime(1980, 1, 1),
                    State = StatesService.GetStates()[1]
                   };
      var personViewModel = new PersonViewModel(person);
      person.AllStates = StatesService.GetStates();
      return View(person);
    }
  }

  public class StatesService
  {
    public static IList<State> GetStates()
    {
      return new List<State>
             {
              new State {Name = "Nebraska", Id = 1},
              new State {Name = "Iowa", Id = 2},
              new State {Name = "Kansas", Id = 3}
             };
    }
  }

  public class Person
  {
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
    public State State { get; set; }
  }

  public class State
  {
    public int Id { get; set; }
    public string Name { get; set; }
  }

  public class PersonViewModel
  {
    public string Name { get; set; }
    public string BirthDate { get; set; }
    public string StateId { get; set; }
    public IList<State> AllStates { get; set; }
  }

Extracting the injection aspect

This leads to repetitive code every time a view model requires this data. Furthermore, we are forced to create the appropriate view model inside the controller action instead of relying on the mapping filter. To separate concerns we created a filter to find these data aspects and inject the values. Now, we simply add a property to the view model and the filter will take care of the rest!

 
  public class InjectStatesFilter : ViewModelInjectFilter
  {
    protected override Func<PropertyInfo,bool> InjectProperty()
    {
      return p => p.PropertyType == typeof (IList<State>);
    }

    protected override object WithValue()
    {
      return StatesService.GetStates();
    }
  }

  public abstract class ViewModelInjectFilter : IActionFilter
  {
    public virtual void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }

    public virtual void OnActionExecuted(ActionExecutedContext filterContext)
    {
      var viewResult = filterContext.Result as ViewResultBase;
      if (viewResult == null || viewResult.ViewData.Model == null)
      {
        return;
      }
      var model = viewResult.ViewData.Model;
      var property = model.GetType().GetProperties().FirstOrDefault(InjectProperty());
      if (property == null)
      {
        return;
      }
      var value = property.GetValue(model, null);
      if (value == null)
      {
        property.SetValue(model, WithValue(), null);
      }
    }

    /// <summary>
    /// The criteria to use to find the property to inject.0
    /// </summary>
    /// <returns></returns>
    protected abstract Func<PropertyInfo,bool> InjectProperty();

    /// <summary>
    /// The value to inject, only queried if a matching, null property is found.
    /// </summary>
    /// <returns></returns>
    protected abstract object WithValue();
  }

Going back to mapping and injecting filters with this new approach helps remove two aspects of duplication from the controller action:

 public class PriorityController : Controller
  {
    public ActionResult Injected()
    {
      var person = new Person
                   {
                    Name = "John Doe",
                    BirthDate = new DateTime(1980, 1, 1),
                    State = StatesService.GetStates()[1]
                   };

      return View(person);
    }
  }

IFilterPriority - Back to the aspect!

In the example, PersonViewModel can be built up with a list of states, if the mapping filter is executed first. To guarantee this, I have added an interface IFilterPriority with a routine GetOrder() to the IJoinedFilter framework. It returns an integer representing the priority of the filter in the execution chain. I chose an integer to mirror FilterAttribute.Order in the MVC framework, which sadly was not made into a compo-sable extensibility point.

 public interface IFilterPriority
  {
    int GetOrder();
  }

JoinedFilterLocator has been modified to add filters based on this order to the FilterInfo result. The actual execution is dependent on the MVC pipeline and follows the following rules when using JoinedFilterLocator:

  • Action Filters
    • High->Low for OnActionExecuting
    • Low->High for OnActionExecuted
  • Authorization Filters - High->Low
  • Exception Filters - High->Low
  • Result Filters
    • High->Low for OnResultExecuting
    • High->Low for OnResultExecuted
 public virtual FilterInfo FindFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  {
    var filters = new FilterInfo();
    var joinedFilters = JoinedFilters
      .Where(i => i.JoinsTo(controllerContext, actionDescriptor)).ToList();

    if (joinedFilters != null)
    {
      AddFilters(joinedFilters, filters.ActionFilters);
      AddFilters(joinedFilters, filters.ExceptionFilters);
      AddFilters(joinedFilters, filters.AuthorizationFilters);
      AddFilters(joinedFilters, filters.ResultFilters);
    }

    return filters;
  }

  private void AddFilters<T>(IEnumerable<IJoinedFilter> joinedFilters, IList<T> filters)
  {
    var orderedFilters = joinedFilters.OfType<T>()
      .OrderByDescending(f => f is IFilterPriority ? (f as IFilterPriority).GetOrder() : int.MaxValue)
      .ToList();

    orderedFilters.ForEach(filters.Add);
  }

Now, we can set the priority of our mapping filter to 1, ensuring it’s OnActionExecuted is executed first. All other filters in the JoinedFilter project are given an order of Int32.Max by default. This might not be the best way to sort, so watch out for updates in the future. This seems to work well with action filters and exception filters.

 public class OnViewResult_IfModelDoesNotMatchViewModelThenMapWithAutoMapper :
    OnViewResult_ExecuteActionFilter<ReflectedAutoMapFilter>
  {
    public override int GetOrder()
    {
      return 1;
    }
  }

Prioritizing exception aspects

Exception filters are another good example where priority becomes important. I have created a sample set of exceptions NestedException inheriting from ExceptionBase. I added two methods to the PriorityController sample:

 public class PriorityController : Controller
  {
    ...
    public void NestedException()
    {
      throw new NestedException();
    }

    public void ExceptionBase()
    {
      throw new ExceptionBase();
    }
  }

  public class ExceptionBase : Exception
  {
  }

  public class NestedException : ExceptionBase
  {
  }

What if we want one handler to catch specific exceptions of type NestedException and another to handle the more general exception ExceptionBase? Without priority, we are at the mercy of JoinedFilterLocator and whatever mechanism it relies on to acquire JoinedFilters. The sample below implements two handlers to send users to an error view with a message reporting what exception handler dealt with the error:

 public class NestedExceptionHandler : ExceptionHandler<NestedException>
  {
    public override int GetOrder()
    {
      return 1;
    }
  }

  public class ExceptionBaseHandler : ExceptionHandler<ExceptionBase>
  {
    public override int GetOrder()
    {
      return 0;
    }
  }

  public abstract class ExceptionHandler<T> : IExceptionFilter, IJoinedFilter, IFilterPriority
    where T : Exception
  {
    public void OnException(ExceptionContext filterContext)
    {
      var exception = filterContext.Exception as T;
      if (exception == null || filterContext.ExceptionHandled)
      {
        return;
      }

      filterContext.Result = ErrorView();
      filterContext.ExceptionHandled = true;
    }

    private ViewResult ErrorView()
    {
      var result = new ViewResult
                   {
                    ViewName = "Error"
                   };
      result.ViewData["Message"] = string.Format("{0} exception handler caught this", typeof (T));
      return result;
    }

    public bool JoinsTo(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
      return true;
    }

    public abstract int GetOrder();
  }

Run the sample yourself and try changing the priority to see how the ExceptionBaseHandler and NestedExceptionHandler work. Notice how this allows control over exception handlers from most specific to most general, just like with try/catch statements.

As usual, all code is available at my Google code repository for IJoinedFilter, this set of changes was wrapped up with commit 56. Please leave me some feedback about any enhancements, specifically I am looking for better ideas to deal with priority of filters, the integer thing kind of bothers me :).

Update: I am thinking that another nice way to do priority would be to use an explicit configuration mechanism, a lot like FubuMvc has so the filters being used are explicit and the order listed is the order applied. Thoughts?

kick it on DotNetKicks.com Shout it

-Wes

1.3.2010

AutoMapFilter meet IJoinedFilter

A few weeks ago I blogged about the concept of a “joined” filter to apply filters to actions without attributes. I promised to demonstrate some practical uses, beyond the hello world example in that post, and now it is time to deliver :)

Jimmy Bogard talks about how he does MVC view models using an AutoMapFilter to transform the model from the controller into the view model for the view. This is an excellent use of AOP to separate the concern of mapping from the concerns in the controller. When I saw this example, I thought to myself, is it possible to infer the types? typeof() always makes code ugly! If this were possible, we could join this filter instead of manually applying it. Here are the steps we would need to accomplish this:

  1. Determine the source type of the model returned from the controller.
  2. Determine the destination type of the view.
  3. Find a reasonable “join point” to apply this filter using IJoinedFilter.

Note: The sample code is located at the original Google Code repository for the IJoinedFilter project.

ReflectedAutoMapFilter

The ideas listed above rely on reflection to discover the source and destination types, so I named the new filter ReflectedAutoMapFilter. It takes a dependency to IReflectedAutoMapper which will do the heavy work. The filter executes after the action, just like Jimmy’s AutoMapFilter:

 public class ReflectedAutoMapFilter : IActionFilter
  {
    public IReflectedAutoMapper ReflectedAutoMapper { get; set; }

    public ReflectedAutoMapFilter(IReflectedAutoMapper reflectedAutoMapper)
    {
      ReflectedAutoMapper = reflectedAutoMapper;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
      ReflectedAutoMapper.TryMapSourceToDestination(filterContext);
    }
  }

ReflectedAutoMapper

Source Type

Getting the source type was straight forward and can also be applied to Jimmy’s original filter.

 var sourceModel = filterContext.Controller.ViewData.Model;
  return sourceModel.GetType();

Destination Type and IViewModelTypeReflector

Here is where the fun begins. This was complex enough it warranted a separate class, IViewModelTypeReflector. I will get into the details of that later. It has a method GetDestinationModelType that takes the ActionExecutedContext and does the voodoo necessary to discover the view model type.

 var destinationType = TypeReflector.GetDestinationModelType(filterContext);

IMapper

Once we have the source and destination types, we can map from the source to the destination. To do this, ReflectedAutoMapper has a dependency to IMapper:

 
  public interface IMapper
  {
    bool HasMap(object source, Type sourceType, Type destinationType);
    object Map(object source, Type sourceType, Type destinationType);
  }

HasMap tells us if the given mapper can perform the mapping. Map performs the mapping and returns the result. The sample code includes two implementations of this for AutoMapper, I will cover them later.

Putting it together in ReflectedAutoMapper

If the mapping is successful, it will put the mapped model into the view’s model property. ReflectedAutoMapper relies on HasMap and also checks to make sure the source type doesn’t already match the destination type before attempting the mapping.
  public class ReflectedAutoMapper : IReflectedAutoMapper
  {
    public IViewModelTypeReflector TypeReflector { get; set; }

    public IMapper ObjectMapper { get; set; }

    public ReflectedAutoMapper(IMapper objectMapper, IViewModelTypeReflector typeReflector)
    {
      TypeReflector = typeReflector;
      ObjectMapper = objectMapper;
    }

    public void TryMapSourceToDestination(ActionExecutedContext filterContext)
    {
      var sourceModel = filterContext.Controller.ViewData.Model;
      if (sourceModel == null)
      {
        return;
      }

      var destinationType = TypeReflector.GetDestinationModelType(filterContext);
      if (destinationType == null)
      {
        return;
      }

      var mapped = Map(sourceModel, destinationType);
      if (mapped != null)
      {
        filterContext.Controller.ViewData.Model = mapped;
      }
    }

    private object Map(object sourceModel, Type destinationType)
    {
      var sourceType = sourceModel.GetType();
      if (sourceType == destinationType
          || !ObjectMapper.HasMap(sourceModel, sourceType, destinationType))
      {
        return null;
      }

      var destinationModel = ObjectMapper.Map(sourceModel, sourceType, destinationType);
      return destinationModel;
    }
  }

ReflectedAutoMapFilter in action

To demonstrate a comparison between this new filter and the original, I created a ReflectedAutoMapAttribute:

 
  public class ReflectedAutoMapAttribute : ActionFilterAttribute
  {
    public ReflectedAutoMapFilter ReflectedAutoMapFilter { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
      ReflectedAutoMapFilter.OnActionExecuted(filterContext);
    }
  }

Here are two actions, one with the original AutoMapFilter and one with the new ReflectedAutoMapFilter.

 
  [AutoMap(typeof (Product), typeof (ProductViewModel))]
  public ActionResult ProductAutoMapFilter()
  {
    var product = new Product
    {
      Id = 1,
      Name = "Product auto map filter"
    };
    return View("Product",product);
  }

  [ReflectedAutoMap]
  public ActionResult ProductReflectedAutoMapFilter()
  {
    var product = new Product
    {
      Id = 1,
      Name = "Product reflected auto map filter"
    };
    return View("Product", product);
  }

Both actions link to the same product view which expects a ProductViewModel:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ProductViewModel>" %>

JoinedReflectedAutoMapFilter

The last step is to join the filter instead of attributing it. View results inherit from ViewResultBase in the MVC framework. By joining to these result types, we can apply any necessary mappings! The join point is any action where the output is, or could be, a ViewResultBase type. Note: IJoinedFilter.JoinsTo was discussed in the post on IJoinedFilter

 
  public class JoinedReflectedAutoMapFilter : JoinedActionFilterAdapterBase<ReflectedAutoMapFilter>
  {
    private const bool JoinToNonReflectedActions = true;

    public override bool JoinsTo(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
      if (!(actionDescriptor is ReflectedActionDescriptor))
      {
        return JoinToNonReflectedActions;
      }

      var returnType = (actionDescriptor as ReflectedActionDescriptor).MethodInfo.ReturnType;

      return JoinToViewResultBaseTypes(returnType)
             || JoinToTypesThatCanHoldViewResultBase(returnType);
    }

    private static bool JoinToTypesThatCanHoldViewResultBase(Type returnType)
    {
      return returnType.IsAssignableFrom(typeof (ViewResultBase));
    }

    private static bool JoinToViewResultBaseTypes(Type returnType)
    {
      return typeof (ViewResultBase).IsAssignableFrom(returnType);
    }
  }

In Action

Now that we are using IJoinedFilter, the action no longer needs the ReflectedAutoMap attribute!

 
  public ActionResult Product()
  {
    var product = new Product
                  {
                    Id = 1,
                    Name = "Product from joined, reflected auto map filter"
                  };
    return View(product);
  }

Demystifying ViewModelTypeReflector : IViewModelTypeReflector

Getting the IView

Getting the destination view model type was easier said than done. It starts with getting the view from the ViewResultBase.

 
  private static IView GetView(ActionExecutedContext filterContext)
  {
    if (!(filterContext.Result is ViewResultBase))
    {
      return null;
    }
    var viewResultBase = filterContext.Result as ViewResultBase;
    var viewName = GetViewName(filterContext, viewResultBase);

    ViewEngineResult result = null;
    if (viewResultBase is ViewResult)
    {
      result = viewResultBase.ViewEngineCollection.FindView(filterContext.Controller.ControllerContext, viewName, (viewResultBase as ViewResult).MasterName);
    }
    else if (filterContext.Result is PartialViewResult)
    {
      result = viewResultBase.ViewEngineCollection.FindPartialView(filterContext.Controller.ControllerContext, viewName);
    }

    if (result == null)
    {
      return null;
    }

    return result.View;
  }

  private static string GetViewName(ActionExecutedContext filterContext, ViewResultBase viewResultBase)
  {
    var viewName = viewResultBase.ViewName;
    if (string.IsNullOrEmpty(viewName)) viewName = filterContext.RouteData.GetRequiredString("action");
    return viewName;
  }

Process

  1. Get the view name - It was interesting to discover that ViewResultBase sets the ViewName, if one isn’t specified, when ExecuteResult is called. Before that, the ViewName is empty, if not explicitly set in the controller. I duplicated the logic in ExecuteResult with GetViewName.
  2. Find the view - different methods are implemented for finding a view if it is partial or not.
  3. Get the view from the ViewEngineResult

Getting the model type - WebFormView

With WebFormViews, the model is not on the view. Instead, it is on the ViewPage which is an extension of the System.Web.UI.Page class. Getting the ViewPage requires a call to the BuildManager for ASP.Net. Once we have the ViewPage we can use the GetModelType method to extract the type of the model using reflection.

 
  if (view is WebFormView)
  {
    return GetWebFormViewModelType(view as WebFormView);
  }

  private static Type GetWebFormViewModelType(WebFormView view)
  {
    var viewPage = BuildManager.CreateInstanceFromVirtualPath(view.ViewPath, typeof (object));
    if (viewPage == null)
    {
      return null;
    }

    var modelType = GetModelType(viewPage);

    TryDispose(viewPage);

    return modelType;
  }

  private static Type GetModelType(object view)
  {
    const string modelPropertyName = "Model";
    var modelMembers = view.GetType().GetMember(modelPropertyName);
    if (modelMembers == null)
    {
      return null;
    }
    var model = modelMembers.OfType<PropertyInfo>().FirstOrDefault(p => p.PropertyType != typeof (object));
    if (model == null)
    {
      return null;
    }
    return model.PropertyType;
  }

Spark views & wrapping up ViewModelTypeReflector.GetDestinationModelType

If the view is from Spark, the Model is a property on it. To keep a dependency from Spark out of the JoinedFilter project, I simply reused the GetModelType method. I have a feeling other view engines might use the same idea with the model property but have not had time to check. If not, this class can be extended as necessary to provide support for other view engines.

 
  public Type GetDestinationModelType(ActionExecutedContext filterContext)
  {
    var view = GetView(filterContext);
    if (view == null)
    {
      return null;
    }

    if (view is WebFormView)
    {
      return GetWebFormViewModelType(view as WebFormView);
    }

    var modelType = GetModelType(view);

    TryDispose(view);

    return modelType;
  }

IMapper & AutoMapper

Mapper.HasMap

If it wasn't enough to have to dig through the heap of madness involving getting to the view model type, I added in a bit more fun using reflection with AutoMapper to add a HasMap method to AutoMapper. I sent a sample patch to Jimmy for inclusion in AutoMapper. In the interim, the reflected version should work fine. Please refer to the implementation of AutoMapperObjectMapper in the sample code for more details. HasMap avoids exceptions when mapping between types without a mapping registered, as is the default with Mapper.Map. This way the filter can silently be ignored and regular exceptions about model type mismatches will show if you have not made a call to CreateMap.

AutoMapperObjectMapper & CreateMap or DynamicAutoMapperObjectMapper

In my sample I glossed over showing the CreateMaps needed to get auto mapper to work. I added these in the static constructor of the controller, other people put them in Application_Start, probably a better spot for them :)

 
  static AutoMappedController()
  {
    Mapper.CreateMap<Product, ProductViewModel>();
    Mapper.CreateMap<Product, OtherProductViewModel>();
  }

Alternatively, we could use the DynamicMap feature of AutoMapper to always perform the mapping:

 
  public class DynamicAutoMapperObjectMapper : IMapper
  {
    public bool HasMap(object source, Type sourceType, Type destinationType)
    {
      return true;
    }

    public object Map(object source, Type sourceType, Type destinationType)
    {
      return Mapper.DynamicMap(source, sourceType, destinationType);
    }
  }

Either way, using the container of your choice, you can inject either strategy.

Registrations

This entire example relies upon a container to inject quite a few dependencies. I refactored a bit of the original IJoinedFilter registrations into JoinedFilterRegistry to separate the concerns a bit. All of my registrations are implemented with Windsor.

JoinedFilterRegistry

These are the components for IJoinedFilter.
 
  public class JoinedFilterRegistry
  {
    public static void Register(IWindsorContainer container)
    {
      container.Register(
        Component.For<IFilterInjector>().ImplementedBy<WindsorFilterInjector>().LifeStyle.Transient);
      container.Register(
        Component.For<IMasterFilterLocator>().ImplementedBy<MasterFilterLocator>().LifeStyle.Transient);
      container.Register(
        Component.For<IFilterLocator>().ImplementedBy<JoinedFilterLocator>().LifeStyle.Transient);
      container.Register(
        Component.For<IActionInvoker>().ImplementedBy<LocatorActionInvoker>().LifeStyle.Transient);
    }
  }

ReflectedAutoMapRegistry

These are the components for the ReflectedAutoMapFilter. This is where you can swap in DynamicAutoMapperObjectMapper :)

 
  public static void Register(IWindsorContainer container)
  {
    container.Register(
      Component.For<IReflectedAutoMapper>().ImplementedBy<ReflectedAutoMapper>().LifeStyle.Transient);
    container.Register(
      Component.For<IViewModelTypeReflector>().ImplementedBy<ViewModelTypeReflector>().LifeStyle.Transient);
    container.Register(
      Component.For<IMapper>().ImplementedBy<AutoMapperObjectMapper>().LifeStyle.Transient);
  }

JoinedRegistry

This is the registry I use in my sample application for the components discussed in this post. It makes a call to JoinedFilterRegistry.Register and then adds its own pieces for the ReflectedAutoMapFilter examples.

 
  private static void RegisterReflectedAutoMapFilter(IWindsorContainer container)
  {
    ReflectedAutoMapRegistry.Register(container);

    container.Register(
      Component.For<IJoinedFilter>().ImplementedBy<JoinedReflectedAutoMapFilter>().LifeStyle.Transient);

    container.Register(
      Component.For<ReflectedAutoMapFilter>().ImplementedBy<ReflectedAutoMapFilter>().LifeStyle.Transient);
  }

Shout it

kick it on DotNetKicks.com

12.19.2009

Testing tips (That is testability, not TDD part 2)

This is a continuation of my last post That is testability, not Test Driven Development! In it, I analyzed an article on the ADO.Net team blog Walkthrough: Test-Driven Development with the Entity Framework 4.0. I wanted to take that analysis a step further and share some insight from the testing perspective itself. There are two tests to review to produce a list of testing tips.

Update: Some of these test refactorings won’t work in the existing sample as they take dependencies to NUnit, you will need to add that in if you want to run these tests.

  1. Don’t setup what we don’t need. Before the first test case was even outlined, a large amount of unnecessary setup was created, some of which was never used. Tip: only write setup specifically for the given test case, in other words write the test case first and then the setup.
    namespace BlogTests
    {
        [TestClass]
        public class CommentTests
        {
            private IBloggingEntities _context;

        [TestInitialize]
        public void TestSetup()
        {
            Person p = new Person()
            {
                fn = "Jonathan",
                ln = "Aneja",
                email = "jonaneja@microsoft.com",
                User = new User() { Password = "password123" }
            };
    
    
            Blog b = new Blog()
            {
                Name = "Entity Framework Team Blog",
                Url = "http://blogs.msdn.com/adonet",
                User = p.User
            };
    
            Post post = new Post()
            {
                ID = 1,
                Blog = b,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Title = "Walkthrough: Test-Driven Development in Entity Framework 4.0",
                User = p.User,
                User1 = p.User,
                PermaUrl = b.Url + "/walkthrough-test-driven-development-in-Entity-Framework-4.0.aspx",
                Body = "This walkthrough will demonstrate how to..."
            };
    
            _context = new FakeBloggingEntities();
    
            var repository = new BlogRepository(_context);
    
            repository.AddPerson(p);
            repository.AddBlog(b);
            repository.AddPost(post);
    
            repository.SaveChanges();
        }
    }
    

    }

  2. Focus on the unit that is being tested, do not test it indirectly. In this example, the first test is to validate that the same comment isn’t added twice, however I see no call to any validate method in the test case!
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void AttemptedDoublePostedComment()
            {
                var repository = new BlogRepository(_context);

            Comment c = new Comment()
            {
                ID = 45,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Body = "EF4 is cool!",
                Title = "comment #1",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            Comment c2 = new Comment()
            {
                ID = 46,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Body = "EF4 is cool!",
                Title = "comment #1",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            repository.AddComment(c);
            repository.AddComment(c2);
    
            repository.SaveChanges();
        }
    
    public class BlogRepository
    {
        private IBloggingEntities _context;
        ...
        public void SaveChanges()
        {
            _context.SaveChanges();
        }
    }
    
    public class FakeBloggingEntities : IBloggingEntities, IDisposable
    {
        public int SaveChanges()
        {
            foreach (var comment in Comments)
            {
                ((IValidate)comment).Validate(ChangeAction.Insert);
            }
            return 1;
        }
    }
    
    public partial class Comment : IValidate
    {
      ...
      void IValidate.Validate(ChangeAction action) {
            if (action == ChangeAction.Insert)
            {
                //prevent double-posting of Comments
                if (this.Post.Comments.Count(c =&gt; c.Body == this.Body &amp;&amp; c.Person.User == this.Person.User) &gt; 1)
                    throw new InvalidOperationException("A comment with this exact text has already been posted to this entry");
            }
        }
    }</pre>The call to validate is indirectly tested through BlogRepository.SaveChanges which calls IBloggingEntities.SaveChanges which is tested with FakeBloggingEntities. FakeBloggingEntities is a stub class and not real code, it’s faking the infrastructure of the EF, when we should be testing our validate method directly. We should rewrite this test as follows and avoid the need for a repository expectation: <pre class="brush: c#">        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AttemptedDoublePostedComment()
        {
            var repository = new BlogRepository(_context);
    
            Comment c = new Comment()
            {
                ID = 45,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Body = "EF4 is cool!",
                Title = "comment #1",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            Comment c2 = new Comment()
            {
                ID = 46,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Body = "EF4 is cool!",
                Title = "comment #1",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            c.Validate(ChangeAction.Insert);
        }</pre>
    

  3. Within a test, avoid unnecessary setup in the scenario (arrange portion). We do not need to set ID,Created,Posted and title for this test case.
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void AttemptedDoublePostedComment()
            {
                var repository = new BlogRepository(_context);

            Comment c = new Comment()
            {
                Body = "EF4 is cool!",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            Comment c2 = new Comment()
            {
                Body = "EF4 is cool!",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            c.Validate(ChangeAction.Insert);
        }</pre>
    

  4. If there are other dependencies for a test case, we should avoid setting them up as global variables. Instead, create them as needed with helper methods. This increases readability and maintainability as we can quickly look at how the person and post are created without going to the setup method. It also decouples the test from the test class so it can be moved if needed when refactoring. Notice we no longer need the repository to pass setup from the setup method to the test case! This is production code that isn’t needed but was added without even testing it! (BlogRepository.GetPersonByEmail & BlogRepository.GetPostByID)
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void AttemptedDoublePostedComment()
            {
                var person = GetNewPerson();
                var post = GetNewPost();
                Comment c = GetNewComment();
                c.Body = "EF4 is cool!";
                c.Person = person;
                c.Post = post;
                Comment c2 = GetNewComment();
                c2.Body = "EF4 is cool!";
                c2.Person = person;
                c2.Post = post;

            c.Validate(ChangeAction.Insert);
        }
    
        private Comment GetNewComment()
        {
            return new Comment();
        } 
    
        private Person GetNewPerson()
        {
            return new Person { User = new User() };
        } 
    
        private Post GetNewPost()
        {
            return new Post();
        } </pre>
    

  5. Avoid duplicated strings. If they have meaning, then share that with a common variable. In this example the body is duplicated for testing validation, so duplicatedBody helps convey that in the name of the variable. Also, avoid meaningful variable values unless they are specific to the test case, to avoid distracting future readers. In this case we should replace duplicatedBody with a valid and simple value to imply that it isn’t important to the test case (“EF4 is cool!” now becomes “A”).
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void AttemptedDoublePostedComment()
            {
                var person = GetNewPerson();
                var post = GetNewPost();
                var duplicatedBody = "A";
                Comment c = GetNewComment();
                c.Body = duplicatedBody;
                c.Person = person;
                c.Post = post;
                Comment c2 = GetNewComment();
                c2.Body = duplicatedBody;
                c2.Person = person;
                c2.Post = post;

            c.Validate(ChangeAction.Insert);
        }</pre>
    

  6. Use AAA test naming to help convey what you are testing and give all variables meaningful names according to the scenario they represent. This method is testing the Validate operation (Act in AAA), the scenario (Arrange in AAA) is a duplicated comment, and the expectation (Assert in AAA) is an InvalidOperationException. The Act_Arrange_Assert naming style from Roy Osherove's The Art of Unit Testing allows test case comprehension without looking at the test code, much like an interface should tell the behavior regardless of implementation! We should rename the comment variables from c and c2 to firstComment and duplicatedComment (Note: if you cannot use var for your type and still understand what the variable represents then you have a misnamed variable).
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void Validate_DuplicatedComment_ThrowsInvalidOperationException()
            {
                var person = GetNewPerson();
                var post = GetNewPost();
                var duplicatedBody = "A";
                var firstComment = GetNewComment();
                firstComment.Body = duplicatedBody;
                firstComment.Person = person;
                firstComment.Post = post;
                var duplicatedComment = GetNewComment();
                duplicatedComment.Body = duplicatedBody;
                duplicatedComment.Person = person;
                duplicatedComment.Post = post;

            firstComment.Validate(ChangeAction.Insert);
        }</pre>
    

  7. Avoid attributed exception assertions as any code in the test could fulfill the assertion. Instead, use inline assertions to test this. In the example below we can setup an action (delegate) that will execute the method under test, then pass that to a method that runs it and will return a failing test if the exception is not thrown (Note: inline exception assertions are a feature in NUnit and several other test frameworks but not in MSTest that I know of).
            [TestMethod]
            public void Validate_DuplicatedComment_ThrowsInvalidOperationException()
            {
                var person = GetNewPerson();
                var post = GetNewPost();
                var duplicatedBody = "A";
                var firstComment = GetNewComment();
                firstComment.Body = duplicatedBody;
                firstComment.Person = person;
                firstComment.Post = post;
                var duplicatedComment = GetNewComment();
                duplicatedComment.Body = duplicatedBody;
                duplicatedComment.Person = person;
                duplicatedComment.Post = post;

            Action validate = () =&gt; firstComment.Validate(ChangeAction.Insert);
    
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }</pre>
    

  8. Arrange test code into three sections, Arrange, Act and Assert (AAA syntax). You will notice we already refactored to this when applying the other tips above. This way the first block of code is always the scenario (arrange), the second block is the action, or deferred action when testing exceptions. Finally the last block is the assertion. Notice how these flow naturally from the AAA test case naming convention. One of the things Roy points out in his book is that if you cannot name a method with AAA syntax then you have not thought through what the method is actually testing. If the authors of the blog post would have named the method with A_A_A syntax and organized it into AAA blocks, they would have noticed the operation under test (Validate) was not mirrored in the test code!
            [TestMethod]
            public void Validate_DuplicatedComment_ThrowsInvalidOperationException()
            {
                // Arrange
                var person = GetNewPerson();
                var post = GetNewPost();
                var duplicatedBody = "A";
                var firstComment = GetNewComment();
                firstComment.Body = duplicatedBody;
                firstComment.Person = person;
                firstComment.Post = post;
                var duplicatedComment = GetNewComment();
                duplicatedComment.Body = duplicatedBody;
                duplicatedComment.Person = person;
                duplicatedComment.Post = post;

            // Act
            Action validate = () =&gt; firstComment.Validate(ChangeAction.Insert);
    
            // Assert
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }</pre>
    

  9. Here is their other test, before applying any of the tips above:
            [TestMethod]
            [ExpectedException(typeof(InvalidOperationException))]
            public void AttemptBlankComment()
            {
                var repository = new BlogRepository(_context);

            Comment c = new Comment()
            {
                ID = 123,
                Created = DateTime.Now,
                Posted = DateTime.Now,
                Body = "",
                Title = "some thoughts",
                Person = repository.GetPersonByEmail("jonaneja@microsoft.com"),
                Post = repository.GetPostByID(1),
            };
    
            repository.AddComment(c);
            repository.SaveChanges();
        }</pre>Here is the test after. The Person and Post properties aren't needed for this test but they are required as the Validate tests with these things for our other test case. If these are part of a “default” test object for a comment we could move them to GetNewComment() and have them available for any test case. <pre class="brush: c#">        [TestMethod]
        public void Validate_BlankComment_ThrowsInvalidOperationException()
        {
            var blankComment = GetNewComment();
            blankComment.Body = string.Empty;
            blankComment.Person = GetNewPerson();
            blankComment.Post = GetNewPost();
    
            Action validate = () =&gt; blankComment.Validate(ChangeAction.Insert);
    
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }</pre>
    

  10. Going back to focusing on the unit itself, needing a post to validate duplicated comments is a smell. This highlights that the concern for validating a duplicated comment should be moved to the post class.
    public partial class Post : IValidate 
    { 
      ... 
      void IValidate.Validate(ChangeAction action) 
      { 
        //prevent double-posting of Comments 
        if (this.Comments.Any(c => this.Comments.Any(other => other != c && other.Body == c.Body && other.Person.User == c.Person.User))) 
          throw new InvalidOperationException("A comment with this exact text has already been posted to this entry");
       } 
    } 

    (Note: this is going to validate existing comments that are duplicated in addition to new ones, but it points out the issue of SRP for validation and that it really belongs here, maybe someone else can point out how we can work with change sets to determine if the duplication was already in place or is new)

    The first test would be moved to PostTests test class. We no longer need the relationship from Comment->Post in our domain, this is domain distillation! Notice how easy it would be to move our first test to a new PostTests class as we don't have a dependency to the setup method! If we needed to share the GetNewXyz() methods we could even move those to a base test fixture.
            // PostTests.cs
            [TestMethod]
            public void Validate_DuplicatedComment_ThrowsInvalidOperationException()
            {
                var person = GetNewPerson();
                var post = GetNewPost();
                var duplicatedBody = "A";
                var firstComment = GetNewComment();
                firstComment.Body = duplicatedBody;
                firstComment.Person = person;
                post.AddComment(firstComment);
                var duplicatedComment = GetNewComment();
                duplicatedComment.Body = duplicatedBody;
                duplicatedComment.Person = person;
                post.AddComment(duplicatedComment);

            Action validate = () =&gt; post.Validate(ChangeAction.Insert);
    
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }
    
        // CommentTests.cs
        [TestMethod]
        public void Validate_BlankComment_ThrowsInvalidOperationException()
        {
            var blankComment = GetNewComment();
            blankComment.Body = string.Empty;
    
            Action validate = () =&gt; blankComment.Validate(ChangeAction.Insert);
    
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }</pre>
    

    Look how simple the second test case is now! Beautiful, the intent is so clear!

  11. Don't write code beyond what a test case expects. In the sample above, we have ChangeAction.Insert as an input to validate but the test doesn’t dictate that in the scenario. We might want this test case to cover both insert and update. We could parameterize the test for both ChangeAction.Insert and ChangeAction.Update. This is using the NUnit framework for parameterized tests. I like to give a distinct name to each of the scenarios when I parameterize a test, so they are explicit when a test runner reports the output of a failure. If we wanted different behavior, we could create two tests but in this case we don't. Be very cautious not to go over board with parameterized tests, they should only be used in the very simplest of test case duplication.
            // CommentTests.cs
            [Test]
            [TestCase(ChangeAction.Insert, TestName="Validate_InsertBlankComment_ThrowsInvalidOperationException")]
            [TestCase(ChangeAction.Update, TestName="Validate_UpdateBlankComment_ThrowsInvalidOperationException")]
            public void Validate_BlankComment_ThrowsInvalidOperationException(ChangeAction changeAction)
            {
                var blankComment = GetNewComment();
                blankComment.Body = string.Empty;

            Action validate = () =&gt; blankComment.Validate(changeAction);
    
            Assert.Throws&lt;InvalidOperationException&gt;(validate);
        }</pre></li></ol>
    

    These are a few testing tips that I use to write and maintain tests every day.

    Happy Testing!

12.19.2009

That is testability, not Test Driven Development!

I applaud efforts to encourage test driven development, however I find myself cringing at the examples being produced by the framework designers we are supposed to look up to. I've noticed this with the buzz around TDD and ASP.Net MVC and now that buzz is transferring to the Entity Framework. I think it is wonderful that these frameworks are designed with testability in mind. However, it is up to the developer to actually employ TDD when composing their applications. There are other ways to test, such as TLD (test last) or just simple TFD (test first) without the extra intricacies of TDD. So enough with TDD and frameworks, just show us the testability! Testability of course being able to test our code that uses your framework, meaning we can isolate your infrastructure from our components.

If you want to demonstrate that for us, just demonstrate it with simple tests of stubs. It’s rather crazy to try to show it through TDD! TDD is a very incremental process that is almost impossible to blog an example about. Anyone who has read Kent Beck's book, yes I said book not blog, knows that by the end he barely produces a handful of tests! This is the very nature of documenting the process, step by step, of using TDD. I guess blog authors just love to get TLAs into their posts, especially TDD, look I did it too! This often leads to confusion about what TDD is and leads many to think it is synonymous with testing.

A very recent example is with the entity framework article “Walkthrough: Test-Driven Development with the Entity Framework 4.0.” This post, from the title, seems to be an example of TDD with EF4. Reading through it, the first test doesn’t get written until step 14! Prior to that a bunch of production code is composed. This is known as TLD (test last). A bunch of unrelated test code is produced before the heart of what they are testing is addressed in step 22. This happens because the author is taking an integration style approach to testing validation from the repository level and not from the class that implements the concern of validation. This leads to all the excess code produced before step 14 and from 15 to 21, not related to the test cases. I can imagine this happened because the author wanted to demonstrate stubbing with a fake repository in EF, which is a good thing to demonstrate, but doesn’t require TDD to demonstrate, SRP of demonstrations please! This post would probably be better named “Walkthrough: Testability with the EF 4.0.” No offense to the author, but please help us readers know what we are getting into, especially if we are learning something new!

The basics of TDD that are missing from this post:

  1. Test list – a list of scenarios that you have yet to write, a simple to do list. As TDD is very involved with one test at a time, this is a scratch pad of future tests.
    1. Items are added as you go
    2. Items are crossed off as they are completed
  2. Red/Green/Refactor workflow
    1. Write test code first
      1. Don’t write unnecessary test code (especially in setup)
        1. Look at the setup method in step 11, we are writing setup without even knowing what our first test case is!
          1. Person – fn,ln,password are never used
          2. Blog – name, url are never used
          3. Post – Created,Posted,Title,PermaUrl (has string concatenation!!!) and Body are never used
        2. Look at the setup in step 14 of AttempteddoublePostedComment
          1. Each comment defines Id, Created, Posted, Body and Title which are never used! Note: Body not being empty would trigger a failure when writing the next test, but you don’t deal with that until you write that test, not when TDDing.
        3. Unnecessary test code decreases maintainability and readability of tests
    2. Get it to compile
      1. Compilation errors are failures
      2. Just enough to get it to pass
    3. Get it to run and fail
      1. Run time failures of expectations
    4. Implement just enough production code to get it to pass under the given scenario
      1. This often means incomplete or incorrect production code, just enough to get it to pass
        1. Why does step 19 implement Attach/Detach methods, why does it implement queryable operations?
        2. Why does step 20 implement GetPersonByEmail, GetPostById? These are smells that we are testing too much at once! This is a unit test smell I will talk about in my next post with testing tips. Some of this is needed because of the integration style testing that is going on in this post, my testing tips will tackle and remove this complexity.
          1. We now have code that isn’t tested in production that likely has needs to be tested. Things like GetPersonById and all the other query/add operations on the BlogRepository!
    5. Refactor
      1. Remove duplication between test and production code, or in production code alone
      2. Perform any other optimizations
    6. Make sure test still passes
    7. Repeat

I hope that this helps clear up some of the confusion that might exist around the differences between testability and TDD. If you want to know more I highly suggest Kent Beck’s book “Test Driven Development: By Example”, it is a great introduction to TDD with fully documented walkthroughs!

See my next blog post where I continue an analysis of this article and offer up some testing tips.

12.11.2009

IJoinedFilter

We have been using ASP.Net MVC for a few projects at work and the standard set of cross cutting concerns are popping up, as usual. A lot of samples exist to create filters for the scenarios (logging, exception handling, mapping, output transformations etc). We have been using many of these and they are adding a lot of excitement to the development process.

However, I smell a bit of a problem with all these attributed filters. The smell of configuration over convention. Configuration isn’t always a bad thing, it’s actually pretty useful when you have niche situations, but when you have repetitive, cross cutting concerns that need the application of the same filters, it gets to be a burden to remember what to apply. The MVC framework is designed with just the right amount of convention over configuration in several other areas, I felt like it was time to do the same for applying filters.

Stealing a page out of the playbook of interception, I felt it was time to design filters to join to actions/controllers when certain criteria are met. Filters themselves are interceptors, so naturally, a filter could define what it joins to, it’s join point (from the interceptor world). This way we have filters apply themselves to actions instead of vice versa! This would be great, for example, to create standard sets of exception filters and have them attached to all actions, no need for someone to decorate every controller and no chance they would forget! The same is true for any type of filter (action, result, authorization or exception).

Note: I also see a need for some SRP with join points and the interceptors and will look into taking existing filters and applying a join point to attach them, instead of the filter needing to define it’s join points.

IJoinedFilter

So enough with the motivation, and on to how this works. IJoinedFilter is an interface to define how a filter should apply to an action and the context:

public interface IJoinedFilter
{
  bool JoinsTo(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}

The method JoinsTo determines if the filter should apply to the current action being executed. Both the controller context and action descriptor are passed to allow for coarse to very fine grained application. Before I explain how to wire up the infrastructure, let's look at an example of how this can be used. Let's say I have a simple controller with two actions, About and World:

public class HomeController : Controller
{
  public ActionResult About()
  {
    var data = new
               {
                message = "about"
               };

return Json(data);

}

public ActionResult World() { var data = new { message = "world" };

return Json(data);

} }

To keep this simple, they both just return json results. The output right now looks like the following:

image image


Now, let’s say I want to use a filter to change my output on the World action to return “Hello world”. Normally I would create a new ActionFilterAttribute and manually apply this attribute:

public class HelloWorldFilter : ActionFilterAttribute
{
  public override void OnActionExecuted(ActionExecutedContext filterContext)
  {
    var result = new JsonResult
    {
      Data = new
      {
        message = "Hello World!"
      }
    };

filterContext.Result = result;

} }

public class HomeController : Controller { public ActionResult About() { var data = new { message = "about" };

return Json(data);

}

[HelloWorldFilter] public ActionResult World() { var data = new { message = "world" };

return Json(data);

} }

HelloWorldFilter

But now, with joined filters I can avoid the step of applying the attribute! Instead I can simply implement IActionFilter with IJoinedFilter to get the same result:

public class HelloWorldFilter : IActionFilter, IJoinedFilter
{
  public bool JoinsTo(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  {
    return actionDescriptor.ActionName == "World";
  }

public void OnActionExecuting(ActionExecutingContext filterContext) { }

public void OnActionExecuted(ActionExecutedContext filterContext) { var result = new JsonResult { Data = new { message = "Hello World!" } };

filterContext.Result = result;

} }

imageJoinsTo is set to only apply to actions with a name of "World". Now, I can replace my World action with a result of "Hello World!" by simply joining to the specific action I want (convention) instead of attributing it (configuration). This is a rather “cheesy” example but I am working on a subsequent blog post to show a few really cool, practical examples!

Infrastructure

Now for how the magic happens. I am going to need to find a spot to discover the joined filters and apply them to an action. The best spot to do this is to create a custom action invoker. I started with the WindsorControllerFactory in MVCContrib, so I also get IoC while I am at it :). This requires overriding the GetControllerInstance. If the container has an IActionInvoker registered, then resolve it and use it instead of the default action invoker.

public class ExtendedWindsorControllerFactory : WindsorControllerFactory
{
  public ExtendedWindsorControllerFactory(IWindsorContainer container) : base(container)
  {
    Container = container;
  }

protected IWindsorContainer Container { get; set; }

protected override IController GetControllerInstance(Type controllerType) { var controller = base.GetControllerInstance(controllerType) as Controller;

if (Container.Kernel.HasComponent(typeof (IActionInvoker)))
{
  controller.ActionInvoker = Container.Resolve&lt;IActionInvoker&gt;();
}

return controller;

} }

Now that I can inject an IActionInvoker, it is time to make one that can find my dynamic filters! I am calling this a LocatorActionInvoker as it resolves a list of IFilterLocator. Each one of these could find filters in it’s own way, this is just for SRP. For each locator the invoker will give it the controller context and the action descriptor and ask it to return filters (FilterInfo). It merges the results of each IFilterLocator into the set of filters to use!

public interface IFilterLocator
{
  FilterInfo FindFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
}

public class LocatorActionInvoker : ControllerActionInvoker { protected IWindsorContainer Container;

public LocatorActionInvoker(IWindsorContainer container) { Container = container; }

protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { var filters = base.GetFilters(controllerContext, actionDescriptor);

var filterFinders = Container.ResolveAll&lt;IFilterLocator&gt;();

var foundFilters = filterFinders.Select(f =&gt; f.FindFilters(controllerContext, actionDescriptor));

foundFilters.ForEach(f =&gt; AddFilters(filters, f));

return filters;

}

private void AddFilters(FilterInfo filters, FilterInfo mergeFilters) { mergeFilters.ActionFilters.ForEach(filters.ActionFilters.Add); mergeFilters.ExceptionFilters.ForEach(filters.ExceptionFilters.Add); mergeFilters.AuthorizationFilters.ForEach(filters.AuthorizationFilters.Add); mergeFilters.ResultFilters.ForEach(filters.ResultFilters.Add); } }

Now I need to implement IFilterLocator to find my IJoinedFilters:

public class JoinedFilterLocator : IFilterLocator
{
  private IWindsorContainer Container;

public JoinedFilterLocator(IWindsorContainer container) { Container = container; }

public FilterInfo FindFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { var filters = new FilterInfo();

var joinedFilters = Container.ResolveAll&lt;IJoinedFilter&gt;()
  .Where(i =&gt; i.JoinsTo(controllerContext, actionDescriptor)).ToList();

if (joinedFilters != null)
{
  joinedFilters.OfType&lt;IActionFilter&gt;().ForEach(filters.ActionFilters.Add);
  joinedFilters.OfType&lt;IExceptionFilter&gt;().ForEach(filters.ExceptionFilters.Add);
  joinedFilters.OfType&lt;IAuthorizationFilter&gt;().ForEach(filters.AuthorizationFilters.Add);
  joinedFilters.OfType&lt;IResultfilter&gt;().ForEach(filters.ResultFilters.Add);
}

return filters;

} }

JoinedFilterLocator uses the container to resolve a list of IJoinedFilter. It filters this list for only filters that apply to the given ActionDescriptor and ControllerContext using the IJoinedFilter.JoinsTo method. If any filters match, it returns them in a new FilterInfo instance, which will be merged in LocatorActionInvoker with the rest of the filters.

Registration

That is it for custom components for the infrastructure of joined filters. All that is left is to configure the application to use the components and to register my components. First I add a container to my application:

public class MvcApplication : HttpApplication
{
  public static IWindsorContainer Container;

Then, in the startup of the application I initialize my container and register my components:

protected void Application_Start()
{
  RegisterRoutes(RouteTable.Routes);
  if (InitializeContainer())
  {
    RegisterControllers();
    SetControllerFactory();
    SetActionInvoker();
    RegisterJoinedActionFilters();
  }
}

Initialize container sets up a Windsor container for the application:

private bool InitializeContainer()
{
  lock (_lock)
  {
    if (Container != null)
    {
      return false;
    }
    Container = new WindsorContainer();
    Container.Register(
      Component.For<IWindsorContainer>()
        .Instance(Container)
        .LifeStyle.Singleton
      );
  }
  return true;
}

If the container is being initialized for the first time, then I register components. RegisterControllers just scans for controllers. SetControllerFactory registers ExtendedWindsorControllerFactory, resolves and sets it as the controller factory for MVC to use.

private void SetControllerFactory()
{
  Container.Register(Component
                      .For<IControllerFactory>()
                      .ImplementedBy<ExtendedWindsorControllerFactory>()
                      .LifeStyle.Transient);

var factory = Container.Resolve<IControllerFactory>();

ControllerBuilder.Current.SetControllerFactory(factory); }

SetActionInvoker registers my LocatorActionInvoker:

private void SetActionInvoker()
{
  Container.Register(Component.For<IActionInvoker>().ImplementedBy<LocatorActionInvoker>()
                      .LifeStyle.Transient);
}

Finally, RegisterJoinedActionFilters registers my JoinedFilterLocator and scans for IJoinedFilter types. You may want to change how this scans based on your project structure, in my simple example I have filters in my MVC app (bad practice but great for samples :)).

private void RegisterJoinedActionFilters()
{
  Container.Register(
    Component.For<IFilterLocator>().ImplementedBy<JoinedFilterLocator>().LifeStyle.Transient
    );

Container.Register( AllTypes.Of<IJoinedFilter>() .FromAssembly(Assembly.GetExecutingAssembly()) .ConfigureFor<IJoinedFilter>(c => c.LifeStyle.Transient) ); }

That is all for now, pretty easy way to setup joined filters and start creating convention based, joined filters instead of manually configuring them via attributes!

Download Sample

If you want to download the sample and try it out, feel free. You probably want an in browser json viewer with this sample, I like using JSONView with FireFox.

Note: due to issues building the latest MVCContrib against MVC 1.0 and/or getting castle version mismatches to work and me being lazy, I simply copied the WindsorControllerFactory into my project for now, cheap yes, but hey my time isn’t unlimited :)

-Wes