in

ASP.NET Weblogs

A Recipe for New Media

September 2009 - Posts

  • My Social Media Adventure #2 -- Using StructureMap as a Controller Factory in ASP.NET MVC

     

     The beautiful thing about ASP.NET MVC is that is contains several extension points (in part #1 we saw how the Model Binder extensions work).  Another extension point that is of great value is the ControllerFactory.  By default, ASP.NET MVC simply looks for a class called {ControllerName}Controller.  So a URL like this:  http://localhost/Home/Index would look for a controller called HomeController because Home is the controller name.  Under the default model factory, you must have a default constructor on your Controller class (you don't actually have to write one as C# will create a default one for you, but if you create a non-default constructor for use in TDD tests, you must explicity write a default constructor, for an example of this concept, take a look at the AccountController that is part of the ASP.NET MVC template project in Visual Studio 2008/2010).  This is fine for simple projects, but once you start getting into more complex projects that utilize services / data access patterns / repositories / etc, you could find yourself writing a lot of redundant code.

    That is why Dependency Injection / Inversion of Control came about.  By using a DI container like StructureMap, you can decouple the services from the controllers and let the DI container worry about them.  So let's start by creating a class that implements the Controller Factory:

     

    public class StructureMapControllerFactory : DefaultControllerFactory
    {
    public StructureMapControllerFactory(IContainer container)
    {
    this.container = container;
    }

    protected override IController GetControllerInstance(Type controllerType)
    {
    try
    {
    return container.GetInstance(controllerType) as Controller;
    }
    catch (StructureMapException)
    {
    System.Diagnostics.Debug.WriteLine(container.WhatDoIHave());
    throw;
    }
    }

    public override void ReleaseController(IController controller)
    {
    base.ReleaseController(controller);
    }

    public IContainer container;
    }

    That's it.  StructureMap has the ability that the first time it sees a new class, it will auto-generate an injection scheme based on the currently registered services.  Let's look at our Global.asax.cs file and see how we use this class:

    protected void Application_Start()
    {
    Container container = new StructureMap.Container();

    container.Configure(x => {
    x.ForRequestedType<IRepository>()
    .CacheBy(InstanceScope.HttpContext)
    .TheDefault.Is.OfConcreteType<NHibernateRepository>();
    });

    ControllerBuilder.Current.SetControllerFactory(
    new StructureMapControllerFactory(container)
    );
    }

    Basically what we have done here is:

    1. Setup StructureMap.  Through we could have used the static class ObjectFactory and made all of our services globally available, I prefer to isolate the services within a private container.
    2. Register the NHibernateRepository class as the implementer of the IRepository pattern.
    3. Set the StructureMap Controller Factory as the default factory for finding controllers.

    We would then rewrite our HomeController to support the IRepository pattern for data lookup as follows:

    public class HomeController {
    private IRepository repository;

    public HomeController(IRepository repo) {
    this.repository = repo;
    }

    public ActionResult Index() {
    var items = repository.GetItems();
    }

    }

    Every time a call was made that used the HomeController, StructureMap would new up a HomeController class, passing in the NHibernateRepository as the parameter to the constructor.  You no longer have to worry about the implementation details of the repository, in fact you could months from now decide to change from using NHibernate to Entity Data Model and all you would have to do is change the one line in your Global.asax.cs that sets the concrete implementation of IRepository to your new repository class, like so:

    x.ForRequestedType<IRepository>()
    .CacheBy(InstanceScope.HttpContext)
    .TheDefault.Is.OfConcreteType<EdmRepository>();

     

    And every single controller in your project that depended on IRepository will start using the Entity Data Model version of your repository without any further changes.

    I will talk about the implementation details of the NHibernateRepository next, it will be a multipart treatment as there is a lot of details in the actual implementation as I use Fluent NHibernate, StructureMap as BytecodeProvider (to provide DI to the data model), and LINQ to NHibernate behind the scenes.  I will also discuss some performance enhancements I made to the repository.

  • My Social Media Adventure #1 -- DataAnnotations Model Binder

    An important part of ASP.NET MVC is the ability to specify a complex object type as the parameter to your controller action method and have MVC "hydrate" your object from the Form data sent to the server by the browser.  For Scott Guthrie's treatment on this feature, go here.  I'm not going to review this functionality.  What I want to talk about is the fact that model validation can be built into the Model Binder so that not only is your object hydrated, it is automatically validated without you ever having to worry about it.  There are several different possible technologies that could be used to do this validation.  I personally looked at:

    • System.ComponentModel.DataAnnotations (Check out Phil Haack's great MIX09 session "Ninja on Fire Blackbelt tips" for an awesome overview of this and other MVC stuff) 
    • NHibernate.Validators

    I ultimately selected DataAnnotations for 3 reasons:

    1. The first and biggest reason I chose DataAnnotations, was one of the requirements I had was localization and I was going to be developing custom validators.  I searched the web over looking for a simple way to do this with NHibernate.Validator and there wasn't one (you actually had to implement an interface, override a default class and lose a bunch of the baked in functionality, not good in my books).  With DataAnnotations, I simply needed to extend the base class ValidationAttribute and all the localization goodness was baked in.
    2. Complexity, NHibernate.Validator uses an attribute and a validator class, which are connected via an attribute on the attribute... Way too complicated (DataAnnotations, the attribute handles validation as well).
    3. DataAnnotation Model Binder is going to be baked into ASP.NET MVC 2.0.

    Now, having made that decision, I began testing with the default DataAnnotations Model Binder sample posted here.  The first thing I realized was that Localization was broken!!  It, thankfully, was an easy fix. I just removed the call to GetDisplayName from the OnModelUpdated as it was unnecessary, and instead of the call to GetDisplayName in OnPropertyValidating, I put this line: 

                validationContext.MemberName = propertyDescriptor.Name;

     And everything started working as expected.  To save you time, I've attached the changed file.  For more information on how to actually implement the DataAnnotations Model Binder, I recommend watching the video referenced above (Ninja on Fire, at position 61:00 of the video, though I highly recommend the whole video).

    (NOTE:  The file really is attached... it is at the very bottom of this post, but if you don't see it... Click Here)

    Ok, having fixed the bug (there was one other bug I heard about, but had not run into yet, about nested complex properties, that I've included the fix for as well), I started writing my custom Validators.  The first of which was CreditCardValidatorAttribute, which (obviously) implements a credit card validation.  So let's look at how I did that.  I'm going to exclude the actual code that does the validation (again, I've included the whole source code in the attachment) and look more at the code specific to DataAnnotations:

    public class CreditCardAttribute : AbstractLuhnAttribute
    {
    public CreditCardAttribute()
    : base(() => Resources.AbstractLuhn_ErrorMessage)
    { }
    }

    That's it.  As I said, I wasn't going to look at the code to do the actual credit card validation (Which is in AbstractLuhnAttribute).  What is happening here is that the ValidationAttribute base class contains a constructor that takes a Func<string> parameter which it will use to lookup the error message. In the constructor of our CreditCardValidator, we pass it a value that comes from the Resources of the DLL containing this validator.

    If you have watched the video as I suggested you would have seen Phil Haack showing you how to define your own Error messages and how to place them into your own Resources within the ASP.NET MVC Web project, all of that example is totally valid with this Credit Card Validator as well!

    The next validator I implemented was a copy of the Future validator from the NHibernate.Validator project, which validated that a date is in the future.  I made a slight modification (due to business rules requirements) and I implemented TodayOrFuture.  It was slightly different from the Credit Card validator in that it's validation message required a more complex token replacement.  So here is the important code (again, the actual validation has been removed, but is included in the attachment to this article. ):

    public class TodayOrFutureAttribute : ValidationAttribute
    {
    public TodayOrFutureAttribute()
    : base(() => Resources.TodayOrFuture_ErrorMessage)
    {
    }

    public override string FormatErrorMessage(string name)
    {
    return string.Format(CultureInfo.CurrentCulture, base.ErrorMessageString,
    new
    object[] { name, DateTime.Now.ToShortDateString() });
    }
    }

    The difference is the FormatErrorMessage method, which allows us to inject a value into the ErrorMessage (which the raw form is

    {0} must be greater than or equal to {1}

    so when you input an incorrect date, you will get an error message that reads like:

    Post Date must be greater than or equal to 09/09/2009

    Again, it makes creating a custom validator extremely easy.  And for those who noticed that I did not involve the Culture in generating the Date string, good eye!  I didn't realize it myself until after I had written this article.  I'm going to fix it in the attachment.

     Up next will be a look at how I integrated StructureMap with the ASP.NET MVC ControllerFactory to provide Dependency Injection to the Controllers.

  • My Social Media Adventure

    Here at Trimedia Atlantic, we've started a new project that I am very excited about, though I cannot yet talk about what that project is, I will talk about my experiences in developing it as we are using a great deal of cutting edge technology, such as a great deal of the NHibernate suite of technologies (Base, Search, etc), StructureMap IoC, AutoMapper, and ASP.NET MVC (along with Telerik's ASP.NET MVC framework).  I have had quite a few moments of excitement as I have discovered the capabilities of the platform(s), moments where the lights came on and I "got" the concepts of why and how, and moments of frustration as things "broke" (or in some cases where never meant to work that way).  I'm going to blog every day about my experiences as I work through the development cycle (but being horrible as I am at blogging, that remains to be seen).

    So here is the list of technologies that I am using:

    • NHibernate 2.1 (Data Access Layer)
    • NHibernate Search (which the source code was a pain to find)
    • Linq to NHibernate (Though not the exclusive data access technology, it is used quite a bit)
    • Castle DynamicProxy2 (for writing some proxy code)
    • ELMAH (Error Reporting)
    • Fluent NHibernate (Fluent management of NHIbernate Config and Entity Mapping)
    • DataAnnotations Model Binder (took the original and fixed some of the problems, such as incorrect handling of Display Attributes, and ported several of NHibernate Validator validators)
    • StructureMap Inversion of Control Container (It's the glue that holds all the other technology together and makes dependency injection so much fun!!  Seriously, I'm loving DI)
    • TweetSharp (Great Twitter integration library)
    • Telerik ASP.NET MVC Extensions (does a great job of managing CSS and JS files, urls, and does file combining and makes using jQuery UI much easier)

    I will warn people right now, my biggest complaint is (and will be) the lack of good documentation for these projects, there has been a lot of trial and error and learning on my part as to how these technologies work (sometimes work best, sometimes I just go them working and will worry about optimization later).  I hope that people benefit from my experience in the course of this blog.

    Post #1 -- DataAnnotations Model Binder
    Post #2 -- Using StructureMap as Controller Factory in ASP.NET MVC
    Post #3 -- Implementing the Repository pattern with NHibernate and Fluent NHibernate
    Post #4 -- Implementing the NHibernate BytecodeProvider with StructureMap
    Post #5 -- Implementing NHibernate.Search

More Posts