Friday, April 09, 2010

NCommon Setup

Today I finally get to a post my friend Dan has been riding me to do for some time. How to setup NCommon and StructureMap with Asp.Net MVC.

Before I get started I want to talk a little about what NCommon is. Simply put, NCommon is a library of commonly used design patterns when developing applications. I took that right from the project website. It was developed by Ritesh Rao. The code can be found at google code. The patterns it implements are as follows...
  1. Unit of Work
  2. Repository using Linq
  3. Validation and business rules
  4. Specification using expressions
  5. Guard class
  6. Utility class
This post wont talk to much about these patterns but future posts will talk about some of them.

So Lets get started.

I will be focusing on the following versions...
ASP.Net MVC version 1.0
StructureMap version 2.5.3
StructureMap Adapter version 1.0
NCommon version 1.0

I plan on updating all version once VS2010 comes out. So there will possibly some differences with the setup if running a later version of ASP.Net MVC.

So my project uses Linq 2 Sql as the backend interface to the database, I could have went with Entity Framework or NHibernate as well since NCommon also supports those as well. While I am at it I did not have to use StructureMap either I could have went with Windsow or Spring or Unity. I just chose StructureMap since I like it best. In the future I might switch to EF 4 or NHibernate with fluent NH but for now I am sticking to Linq 2SQL and StructureMap.

So the first thing you need to do is set up you StructureMap Container and store it in the NCommon.Storage.Store.

In the container setup you need to register some things.


public static Container BuildContainer()
{
Container container = new Container(x =>
{
//ncommon
x.ForRequestedType().CacheBy(InstanceScope.Hybrid).TheDefaultIsConcreteType();
x.ForRequestedType(typeof(IRepository<>)).CacheBy(InstanceScope.Hybrid).TheDefaultIsConcreteType(typeof(LinqToSqlRepository<>));
x.ForRequestedType().CacheBy(InstanceScope.Hybrid).TheDefault.Is.ConstructedBy(
() => new DataModelDataContext(ConfigurationManager.ConnectionStrings["ConnectionStringNameFromWeb.Config"].ConnectionString));


//Other project items here.....
});

container.AssertConfigurationIsValid();
return container;
}


So what is going on here... We create a new StructureMap container and tell it how to create objects when asked for a certain object. the first line we tell the container when asked for IUnitOfWorkFactory we want it to return LinqToSqlUnitOfWorkFactory since I am using Linq2Sql. If I was using EF I would have set it up to return EFUnitOfWorkFactory. The same goes for typeof(Irepository<>) we have it return typeof(LinqToSqlRepository). Finally we tell the container how to create our DataContext.

So How do we call this method. Well in the global.asax.cs file is how.

protected void Application_Start()
{
ConfigureContainer();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new IocControllerFactory());
LinqToSqlUnitOfWorkFactory.SetDataContextProvider(GetDataContext);
}

private void ConfigureContainer()
{
Container container = StructureMapBootStrapper.BuildContainer();

Store.Application.Set("ApplicationContainer", container);

ServiceLocator.SetLocatorProvider
(
() => new StructureMapServiceLocator(Store.Application.Get ("ApplicationContainer"))
);

}


So as you can see on the app startup we call ConfigureContainer and that method calls our build container and then sets the container on the Store. We then use the ServiceLocator and tell it how to find our newly created container. BTW.... the Service locator is part of the Common Service Locator Library from Microsoft using the StructureMap Adapter.

The Next important thing we need to do is tell MVC how to inject our controllers. If you see in the code above ControllerBuilder.Current.SetControllerFactory(new IocControllerFactory()); This code tells MVC to use a ControllerFactory I created instead of the default. Note the following code will not work in MVC 2.0.


public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
IController result = null;
if (controllerType != null)
{
try
{
IContainer container = Store.Application.Get("ApplicationContainer");
result = container.GetInstance(controllerType) as Controller;

//result = ObjectFactory.GetInstance(controllerType) as Controller;
}
catch (StructureMapException)
{
System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
throw;

}
}

return result;
}
}


As you can see what we are doing is we are asking the Store for our container and trying to find the requested controller. StructurMap is smart in that if we did not define it in the registry it will try to create it itself using the greasiest constructor.

Finally the last thing we need to set the DataContext on the LinqToSqlUnitOfWorkFactory. again from teh app startup method in the global.asax.cs file we do this LinqToSqlUnitOfWorkFactory.SetDataContextProvider(GetDataContext); where GetDataContext is a property that looks like this


private DataContext GetDataContext()
{
return (DataContext)Store.Application.Get("ApplicationContainer").GetInstance(typeof (DataContext));
}


All it does is ask the store for our container and ask it for the DataContext.

That was how I set up my application to use NCommon. In the next post I will talk more about NCommon and some of the patterns. Stay tuned.
Post a Comment