Factory Pattern using Windsor and MVC

I ran into a situation where I wanted to return a dynamically drawn image based on the file name . For example, if someone requested somedomain.com/image/legacypage42.foo the “legacypage42.foo” would be the name of the Windsor component used to draw the image. The first thing I needed to do was change that page into a parameter which is very simple with MVC .net routing:
  
routes.MapRoute("MyImageRoute",
                "image/{filename}",
                new { controller = "Images", action = "Index" });

So now filename becomes the parameter in the controller. Now comes the tricky part. How to resolve a component in Windsor by name. Windsor does allow you to set the name using this syntax:
  
kernel.Register(
    Component.For<IMyImageComponent>()
        .ImplementedBy<MyImageComponent>()
        .Named("SomeImage"));

Although, using that syntax is going to make for a nightmare if I have many different image components so I’ll use the built in Windsor Type Factory. The first step is to cleanly register all my image components setting the name. To do that I created an interface all my images will use so I can easily set the named value.
  
Interface example:

    public interface IMyImageComponent
    {
        Bitmap BuildImage();

        string GetFileName();
    }

Here is how I use the interface to setup my Windsor components and named values.
  
var type = typeof(IMyImageComponent);
            var styles = AppDomain.CurrentDomain.GetAssemblies().ToList()
                .SelectMany(s => s.GetTypes())
                .Where(type.IsAssignableFrom);

            //find all classes that implement IMyImageComponent and register using name from GetFileName()
            foreach (var style in styles)
            {
                if (!style.IsClass || style.IsNotPublic || style.IsAbstract)
                    continue;

                object o = Activator.CreateInstance(style);
                var propertyInfo = style.GetMethod("GetFileName");
                var name = (string)propertyInfo.Invoke(o, null);
                container.Register(Component.For<IMyImageComponent>().ImplementedBy(o.GetType()).Named(name));

Here is how the factory was initialized:
  
            container.Register(Component.For<ITypedFactoryComponentSelector>().ImplementedBy<ImageStyleFactorySelector>().Named("ImageStyleFactorySelector"));

            container.Register(Component.For<IMyImageTemplateFactory>()
                .AsFactory(c => c.SelectedWith("ImageStyleFactorySelector")));

Notice I used a custom selector in the factory. This is used when the factory is looking up the components. Here is what the FactorySelector looks like.
  
public class ImageStyleFactorySelector : DefaultTypedFactoryComponentSelector
    {
        protected override string GetComponentName(MethodInfo method, object[] arguments)
        {
            if (method.Name == "GetByFileName" && arguments.Length == 1 && arguments[0] is string)
            {
                return arguments[0].ToString();
            }
            return base.GetComponentName(method, arguments);
        }
    }

Now inside the controller I use the factory with the function “GetByFileName” which uses the custom selector to find the component.
  
var imageComponent = _ImageTemplateFactory.GetByFileName(fileName);

Posted in | Tagged , , , | Comments Off