2011-04-23

ASP.NET MVC and Unity

,

What is Unity?

The Unity Application Block (Unity) is a lightweight extensible dependency injection container with support for constructor, property, and method call injection. Dependency injection is used to create loosely coupled applications. These kind of applications are easier to maintain and easier to test.

What do we want to achieve?

We want to make our controllers loosely coupled and break any hard dependencies it has. Every object/resource that our controller needs, has to be automatically populated and correctly initiated by Unity.

The Asp.net mvc application

This is the HomeController that we have in our application.

    public class HomeController : Controller
    {
        ITitleRepository _titleRepository = null;

        public HomeController()
        {
            _titleRepository = new TitleRepository();
        }

        //
        // GET: /Home/
        public ActionResult Index()
        {
            ViewBag.Title = _titleRepository.GetTitle("Index");

            return View();
        }
    }

As you can see, it uses a TitleRepository. This repository is used to determine which title has to be rendered on a specific page.  

            _titleRepository = new TitleRepository();

This is the line that we want to remove. With this, we make a hard dependency between our HomeController and the TitleRepository.

    public interface ITitleRepository
    {
        string GetTitle(String page);
    }

    public class TitleRepository : MVCWebsite.Repository.ITitleRepository
    {
        public String GetTitle(String page)
        {
            return String.Format(" This is a Title for the page: {0}", page);
        }
    }

 

Using Unity

Adding references

Add the Microsoft.Practices.Unity dll to you project. Unity can be found at http://unity.codeplex.com/.

Creating a custom LifetimeManager

When you register a type with Unity, you can also specify a lifetime of this type. If you don’t specify a lifetime, Unity will create a new instance of that type each time that the type is requested. In an Asp.Net application, we can make the LifetimeManager cache or store the created objects in the HttpContext HttpSession or HttpApplication. In my case, i want a singleton per request.

    public class HttpContextLifetimeManager<T> : LifetimeManager
    {
        public override void SetValue(object newValue)
        {
            HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
        }

        public override object GetValue()
        {
            return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
        }

        public override void RemoveValue()
        {
            HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
        }  
    }

Creating the UnityContainer

Next in line is the creation of a UnityContainer. This container will be used to resolve certain types. In order to work, we have to register these types. In our case, we our going to register the ITitleRepository type with the TitleRepository type. This will mean that if we ask the container to resolve the ITitleRepository, it will return a TitleRepository object. As you see, i pass the HttpContextLifetimeManager as parameter.

public class UnityConfigurator
{
    public static IUnityContainer GetContainer()
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ITitleRepository, TitleRepository>(new HttpContextLifetimeManager<ITitleRepository>());

        return container;
    }
}

Now we are registering our type hardcoded. It is also possible doing this in the config file.

Creating a Controller Factory

We need to create a custom Controller factory to replace the default factory that is used by the MVC framework. Our factory accepts a IUnityContainer as parameter. This container contains all the types we registered.

We only need to override the GetControllerInstance method. In this method we have to use the container to create an instance of the requested controller. This way, Unity will automatically resolve the requested types for this controller. In our case: ITitleRepository.

    public class UnityControllerFactory : DefaultControllerFactory
    {
        IUnityContainer container = null;

        public UnityControllerFactory(IUnityContainer container)
        {
            this.container = container;
        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            IController result = null;

            if (null != controllerType)
            {
                result = container.Resolve(controllerType) as IController;
            }

            return result;
        }
    }


Now we have to tell the MVC framework to use the UnityControllerFactory as it’s default controller factory. This is done best in the global.asax, in the Application_Start method.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(UnityConfigurator.GetContainer()));
}

 

Breaking the dependency

Now we have to modify our HomeController. We change it’s constructor to accept an object of the ITitleRepository type.

    public class HomeController : Controller
    {
        ITitleRepository _titleRepository = null;

        public HomeController(ITitleRepository titleRepository)
        {
            _titleRepository = titleRepository;
        }

        //
        // GET: /Home/
        public ActionResult Index()
        {
            ViewBag.Title = _titleRepository.GetTitle("Index");

            return View();
        }
    }

The result

When we go to the index of the HomeController, our UnityControllerFactory comes in action and Untity will inject the TitleRepository in the constructor of the HomeController.

When i want to use another implementation of the ITitleRepository, i only have to change the GetContainer method of the UnityConfigurator and the HomeController will automatically be injected with the new implementation.

    public class TitleRepository2 : MVCWebsite.Repository.ITitleRepository
    {
        public string GetTitle(String page)
        {
            return String.Format("{0} is the Title for this page!", page.ToUpper());
        }
    }

public class UnityConfigurator
{
    public static IUnityContainer GetContainer()
    {
        IUnityContainer container = new UnityContainer();

        container.RegisterType<ITitleRepository, TitleRepository2>(new HttpContextLifetimeManager<ITitleRepository>());

        return container;
    }
}

Read more →

2011-04-06

NHibernate in combination with a webservice

,

In this post i ‘ill try to explain how you can make NHibernate interact with a webservice to fill in a certain object.

Current situation

This is the current situation that we have.

  Current situation

 

We have a webservice called “Marial State service”. This service is responsible for all marial states available.
This service has only 2 methods:

  • GetAll()
    • Gives all the available marial states
  • GetById(Int32 id)
    • Gives a specific marial state by it’s id

The client is an application that has it’s own database and uses NHibernate as ORM. The client is responsible for creating/updating/deleting persons in his database. So in the database we find a table called “Person” with contains all the data.

 Person Table

As you can see, the person, has a marial state which comes from the MarialState service.
For those who noticed, yes i am using an Access as database. Here you can find the needed DLL.

The MarialState service

I created 2 new projects in visual studio. One which contains the model off the service.

 Webservice Model

namespace NHibernateWebservices.WebServiceProxy.Model
{
    public class MarialState
    {
        public Int32 Id { get; set; }
        public String Description { get; set; }
    }
}


And another project for the service logic. As you can see this isn’t a real service. I am mocking it.

 Webservice Logic

namespace NHibernateWebservices.WebServiceProxy
{
    public static class MarialState
    {
        public static List<Model.MarialState> GetAll()
        {
            return new List<Model.MarialState>
                                {
                                    new Model.MarialState { Id = 1, Description = "Single"}
                                    ,new Model.MarialState { Id = 2, Description = "Married"}
                                    ,new Model.MarialState { Id = 3, Description = "widower"}
                                };
        }

        public static Model.MarialState GetById(Int32 id)
        {
            return GetAll().SingleOrDefault(m => m.Id == id);
        }
    }
}

The client

At client side the we created a business object  called “Person” which will map at the Person table in it’s database.

public class Person
{
    public virtual Int32 Id { get; set; }
    public virtual String FullName { get; set; }
    public virtual Int32 MarialStateId { get; set; }
}

This is the mapping file for the “Person” entity.

<?xml version="1.0" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="NHibernateWebservices.Model.Person, NHibernateWebservices.Model"
         table="Person">
    <id name="Id"
        column="Id"
              unsaved-value="0">
      <generator class="increment" />
    </id>
   
    <property column="FullName"
              name="FullName"
              type="String" />

    <property name="MarialStateId"
             column="MarialStateId"
             type="int"/>
   
  </class>
</hibernate-mapping>

 

Now How to get the data?

First try

The most easy way to get the MarialState entity would be to write something like this.

public class Person
{
    public virtual Int32 Id { get; set; }
    public virtual String FullName { get; set; }      

    private Int32 marialStateId;
    public virtual Int32 MarialStateId
    {
        get
        {
            return marialStateId;
        }
        set
        {
            marialStateId = value;
        }
    }

    public virtual WebServiceProxy.Model.MarialState MarialState
    {
        get
        {
            return WebServiceProxy.MarialState.GetById(marialStateId);
        }
        set
        {
            marialStateId = (null == value) ? (0) : (value.Id);
        }
    }
}

This solution will work, but I can see several things that I am not happy with. First of all it’s a lot off extra code. In this case the “Person” entity is very simple, but what if it was complex and you needed to get other data from a service, you would be writing a lot of code looking like this.

Second, in this approach you need to create a reference between the WebServiceProxy and the business Model of the client. At this point the business Model of the client is also responsible to fill it’s own data instead of only validating against business rules.

Using NHibernate IUserType

The ideal situation would that we ask NHibernate to give use a “Person” and that everything, including MarialState object, would be filled automatically. You can do this if you create a new NHibernate IUserType object. IUserType is an interface which allows you to plug in into the NHibernate mapping process and handle it your self.

public class MarialStateUserType : IUserType
{
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public bool IsMutable
    {
        get { return true; }
    }

    public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
    {
        object obj = NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
        WebServiceProxy.Model.MarialState marialState = null;

        if (null != obj)
        {
            marialState = WebServiceProxy.MarialState.GetById(Convert.ToInt32(obj));
        }

        return marialState;
    }

    public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
    {
        WebServiceProxy.Model.MarialState marialState = value as WebServiceProxy.Model.MarialState;

        var parameter = (IDataParameter)cmd.Parameters[index];
        if (null == marialState)
            parameter.Value = DBNull.Value;
        else
            parameter.Value = marialState.Id;
    }

    public Type ReturnedType
    {
        get { return typeof(WebServiceProxy.Model.MarialState); }
    }

    public SqlType[] SqlTypes
    {
        get { return new SqlType[] { NHibernateUtil.Int32.SqlType }; }
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public new bool Equals(object x, object y)
    {
        if (object.ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.Equals(y);
    }
}

This it the custom IUsertype that is created for the MarialState entity. In this example, these are the most interesting parts of code:

  • ReturnedType
  • SqlTypes
  • NullSafeGet
  • NullSafeSet

 

ReturnedType/SqlTypes properties

The ReturnedType and SqlTypes properties tells NHibernate which type to expect. The ReturnedType property contains the type of object that this IUsertype has to return. In our case it is a MarialState object.

public Type ReturnedType
{
    get { return typeof(WebServiceProxy.Model.MarialState); }
}

The SqlTypes property tells how the object is mapped in the database. Here the MarialState object is mapped to a numerical column.

public SqlType[] SqlTypes
{
    get { return new SqlType[] { NHibernateUtil.Int32.SqlType }; }
}

NullSafeGet/NullSafeSet methods

The NullSafeSet method is called when we want to save/update our object. In our case, the parameter ”value” will contain our MarialState entity. The parameter “cmd” will contain the command that is used to update/insert the “Person” entity in the database.

What we now have to do, is to insert the Id of the MarialState entity in the command at the index place. We know the index because it is passed to the NullSafeSet method. If the MarialState entity is empty, we insert the DBNull value.

public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index)
{
    WebServiceProxy.Model.MarialState marialState = value as WebServiceProxy.Model.MarialState;

    var parameter = (IDataParameter)cmd.Parameters[index];
    if (null == marialState)
        parameter.Value = DBNull.Value;
    else
        parameter.Value = marialState.Id;
}

The NullSafeSet method is called when we want to extract the data from the database. This method will return a MarialState entity. As you can see, this method has a IDataReader object as parameter. From this IDataReader we have to extract the MarialStateId column and use it‘s value to get the MarialState entity from the MarialState service. We also do a check to see if the value isn’t null because it could be NULL in the database.

public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
{
    object obj = NHibernateUtil.Int32.NullSafeGet(rs, names[0]);
    WebServiceProxy.Model.MarialState marialState = null;

    if (null != obj)
    {
        marialState = WebServiceProxy.MarialState.GetById(Convert.ToInt32(obj));
    }

    return marialState;
}

 

Putting the pieces together

Now that everything is in place, we can start to glue it together. First of all, we can change the “Person” entity at the client. The property MarialStateId can now be replaced by the MarialState property. The class looks a lot cleaner this way.

public class Person
{
    public virtual Int32 Id { get; set; }
    public virtual String FullName { get; set; }

    public virtual WebServiceProxy.Model.MarialState MarialState { get; set; }
}

Next in line is to change the mapping file for the “Person” entity. In this file we are going to make use of the MarialStateUserType that we created.

<?xml version="1.0" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="NHibernateWebservices.Model.Person, NHibernateWebservices.Model"
         table="Person">
    <id name="Id"
        column="Id"
              unsaved-value="0">
      <generator class="increment" />
    </id>
   
    <property column="FullName"
              name="FullName"
              type="String" />

    <property name="MarialState"
              column="MarialStateId"
              type="NHibernateWebservices.NHibernateUserType.MarialStateUserType, NHibernateWebservices"/>
   
  </class>
</hibernate-mapping>

If we run the client and get a “Person” from the database, the MarialState will be filled automatically be NHibernate.

What about the performance?

If you have some performance problems, you can always but lazy loading on the MarialState property. This way we will only go to the service if we use the MarialState property.

<property name="MarialState"
          column="MarialStateId"
          lazy="true"
          type="NHibernateWebservices.NHibernateUserType.MarialStateUserType, NHibernateWebservices"/>
Read more →