Sunday, May 2, 2010

Autofac 2.2 and Me: My First Look at an IoC

Well, since I had the database audit working to my satisfaction (not to a production multi server high volume level, but working enough), it is now time to start working on my c# code skills.  While I am working to get a system working, I am not specifically wanting to achieve a specific project like I was for the audit, but rather making sure I am playing with various technologies.  Things like C#, WCF, Silverlight, maybe some WPF, and MVC.  Any other things I should be trying just let me know.

So, my first learning is going to be the concept of an IoC container. Here are the simple steps I took to implement it.  Please note I have not any direct experience with IoC containers, and only a weeks worth of reading here and there on Autofac and IoC containers.  This basically means that I have gotten it working, but it isn't necessarily the best implementation, so please, any feedback would be appreciated.

But before I explain how I got it working, let me explain (to my understanding) why you should be using an IoC Container.  One of the hardest things to do is make any major changes to an existing system.  This is because they are usually written with a single objective in mind, to fulfil the requirements.  Now, when you want to change a part of your code, it is simple.  However, if you want to remove an entire section of the code (for example change the database type), this gets harder.  Using interfaces has helped with this, in that you can write to an interface, and when you want to change the implementation you can create another version to the interface, and substitute it with the old version.  But, the down side is that you need to find all the references and update them.  Here is where IoC Containers come into play.

With an IoC container, in one place you can change the implemented class, where the IoC is built, rather than having to find every instantiation of the old class to change it to the new one.  This can lead to a more decoupled application, one that has as many of its parts (code wise) not reliant on the other parts, but on definitions of what the code is meant to do.  As a result, these parts can be interchanged with greater ease.

Now, back to the implementation of the Autofac IoC container.

The Steps to IoC Goodness

  1. Downloaded the source
  2. Added the resources to my projects
  3. Created the Container
  4. Updated my code to use the container
Downloaded the source
The first step was to download the source from the project home.  The homepage of the Autofac project is here, and the download page is here. Please note that there is a .Net 3.5 version and a 4.0 version, so choose the version that best suits you. (Or best suits your code, to be more precise.)

Added the resources to my projects
Next, I added the dll files to my projects.  I added them to my code project and also the test project.  The code project cause that is where object interfaces and the like are registered with the IoC Container, but also in my test project cause that is where the container is tested to make sure that I have gotten the container working properly (the whole point of a test).

Created the Container
Next, in my project, I added the container to my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Autofac;

namespace Nyx.Core.Universal
{
public sealed class AutofacContainer
{
// Added a private constructor to stop the auto creation of a public one
private AutofacContainer()
{
}

public static IContainer BuildContainer()
{
var builder = new ContainerBuilder();

builder.RegisterType<DatabaseSession>().As<IDatabaseSession>();
builder.RegisterType<DataAccessTest>();

var container = builder.Build();
return container;
}

}
}

Please note that the basis of this is to prove a test, to make sure that the code is functioning properly.  The constructor for the DataAccessTest object has a dependency on IDatabaseSession (see the DataAccessTest code below). Now, note that the 2 register statements are different.  This is because I am in the first case, telling Autofac that when it sees the interface IDatabaseSession it should use the concrete class DatabaseSession.  This is not actually required, as but am just learning so I explicitly code it that way.  If you see the second register line, you will see that it is just registering the class, no interface reference.  This is how I could have written the first line, the interface being inferred.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nyx.Core.Entities;
using Nyx.Core.Universal;
using NHibernate.Linq;

namespace Nyx.Core
{
public class DataAccessTest
{
IDatabaseSession _sessionLocator;

public DataAccessTest(IDatabaseSession sl)
{
_sessionLocator = sl;
}

public User GetUser()
{
User result = null;

using (var session = _sessionLocator.OpenSession())
{
var query = from ticketingOffer in session.Linq<User>()
where ticketingOffer.UserId.Equals(1)
select ticketingOffer;
result = query.FirstOrDefault();
}
return result;
}
}
}

The database session is just a connection that through fluent nHibernate connects to a MS SQL 2008 Express edition database, and I wont bore you with that code.

4. Updated my code to use the container


So, I have updated the code by adding the IoC container to the core, and creating a test class to prove my point, I have written a unit test to show that it is all working.

[TestMethod]
public void Autofac_database_integration_test_should_return_valid_user()
{
using (var container = AutofacContainer.BuildContainer())
{
var TestObject = container.Resolve<DataAccessTest>();
var result = TestObject.GetUser();

Assert.AreEqual(1, result.UserId);
Assert.AreEqual("lkoutzas", result.UserName);
}
}

Now, this code creates the Autofac IoC, and then it resolves the DataAccessTest class, automatically resolving the DatabaseSession class.


And there you have it.  I haven't added everything that I have done, just the highlights to get Autofac working.  Again, this is my getting it working, not the implementation of a pattern or anything.


Happy Containing!

No comments:

Post a Comment