REST using the WCF Web API – refactoring to IoC style (Part 3)

Written on April 18, 2011

Postings published on this series so far:

Recap

In the previous posting I gave you a short introduction to the shiny new WCF Web API from Microsoft.

Of course the shown implementation is faraway from being a real world application sample -- so let's get started to move things forward.

When looking again at our ContactsResource there is at least one thing that (hopefully) won't happen in real world code:

[ServiceContract]
public class ContactsResource {
    [WebGet(UriTemplate = "")]
    public List<Contact> Get() {
        return new List<Contact>()
                {
                       new Contact()
                           {
                               Id = 1,
                               Name = "Glenn Block"
                           },
                       new Contact()
                           {
                               Id = 2,
                               Name = "Scott Hanselman"
                           },
                       new Contact()
                           {
                               Id = 3,
                               Name = "Scott Guthrie"
                           }
                };
    }
}

Moving forward

As you can see, our List of Contacts is instantiated by hand.

This for sure won't happen in a real world application happen because it is likely that our contacts are stored in a database.

Thus it will also be likely, that we'll have an Repository handling the CRUD-stuff against this database.

This will make our ContactsResource look like this:

[ServiceContract]
public class ContactsResource {
    [WebGet(UriTemplate = "")]
    public List<Contact> Get() {
        ContactRepository repository = new ContactRepository();
        return repository.Get();
    }
}

Whereas the ContactRepository looks like this:

public class ContactRepository {
    public List<Contact> Get() {
        return new List<Contact>()
            {
                   new Contact()
                       {
                           Id = 1,
                           Name = "Glenn Block"
                       },
                   new Contact()
                       {
                           Id = 2,
                           Name = "Scott Hanselman"
                       },
                   new Contact()
                       {
                           Id = 3,
                           Name = "Scott Guthrie"
                       }
            };
    }
}

Ok, this is much better now.

Guess what: It's faraway from that.

It's not the fact, that we're new'ing up the Contacts themselves in the Repository as I don't want to code down the complete Repo for demo.

Instead we didn't make an progress to the previous version as we're now simply instantiating the ContactRepository instead of the List of contacts inside our ContactsResource.

In terms of testing we now have an dependency on the database by referencing to the concrete instance of our contacts repository.

Your CI server may have other database settings (or even worse: no database installed at all) than your local machine and your tests will fail miserably.

Poor boy!

In order to get rid of instantiating our repository inside our ContactsResource we will pass it to our constructor and further more, we'll extract an interface called IContactRepository in order to be able to exchange the concrete implementation of our repository whenever we want to.

Doing it this way is a pattern called dependency injection.

Our updated code:

[ServiceContract]
public class ContactsResource {
    readonly IContactRepository _contactRepository;

    public ContactsResource(IContactRepository contactRepository) {
        _contactRepository = contactRepository;
    }

    [WebGet(UriTemplate = "")]
    public List<Contact> Get() {
        return _contactRepository.Get();
    }
}

public interface IContactRepository {
    List<Contact> Get();
}

public class ContactRepository : IContactRepository {
    public List<Contact> Get() {
        return new List<Contact>()
            {
                   new Contact()
                       {
                           Id = 1,
                           Name = "Glenn Block"
                       },
                   new Contact()
                       {
                           Id = 2,
                           Name = "Scott Hanselman"
                       },
                   new Contact()
                       {
                           Id = 3,
                           Name = "Scott Guthrie"
                       }
            };
    }
}

Yet, there's another problem: Who will instantiate our Repository?

In terms of our ASP.NET MVC application hosting the ContactsResource, this is done inside theGlobal.asax.cs file.

You may remember ContactResourceFactory:

public class ContactResourceFactory : IResourceFactory {
    public object GetInstance(Type serviceType, InstanceContext instanceContext, HttpRequestMessage request) {
        return new ContactsResource();
    }

    public void ReleaseInstance(InstanceContext instanceContext, object service) {
        throw new NotImplementedException();
    }
}

Using this our code won't compile now, because the instantiation of the ContactsResource is missing the IContactRepository instance.

How do we pass it in then?

One way could be -- as already written -- instantiate the dependency by ourselves inside the global.asax.cs.

When having only a few dependencies, this may be ok. But speaking of a real application you'll have tons of them and you don't want to take care of them the whole day.

But we're fortunate. Lots of people ran into this before and solved it by creating so called IoC-Containers whose job is to create instances of our classes and handle dependencies between them.

My favorite IoC-Container is LightCore and of course, it is available through Nuget.

After adding the Library Package Reference to our project, we'll update our code as follows -- starting with the updated RegisterRoutes method in Global.asax.cs:

public static void RegisterRoutes(RouteCollection routes) {
    ContainerBuilder builder = new ContainerBuilder();
    builder.Register<IContactRepository, ContactRepository>();
    builder.Register<IResourceFactory, LightCoreResourceFactory>();
    IContainer container = builder.Build();

    var configuration = HttpHostConfiguration.Create()
        .SetResourceFactory(new LightCoreResourceFactory(container));
    RouteTable.Routes.MapServiceRoute<ContactsResource>("contacts", configuration);
}

The LightCore IoC container mainly consists of a class namely ContainerBuilder and an interface called IContainer and works this way:

A ContainerBuilder instance registers all dependencies by calling its Register method and passing in the interface name and the concrete type to be instantiated on application startup.

When registration is done, an IContainer is build by the ContainerBuilder calling its Build method.

The created container is passed into the LightCoreResourceFactory (formerly known as ContactResourceFactory).

The fact that we're using the IoC container now, leads to a generic implementation of the LightCoreResourceFactory:

public class LightCoreResourceFactory : IResourceFactory {
    readonly IContainer _container;

    public LightCoreResourceFactory(IContainer container) {
        _container = container;
    }

    public object GetInstance(Type serviceType, InstanceContext instanceContext, HttpRequestMessage request) {
        return _container.Resolve(serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object service) {
        throw new NotImplementedException();
    }
}

As you can see, there's no reference to the ContactsResource or the ContactRepository at all inside the ResourceFactory.

Thus we don't need another Factory when adding further Resources.

In fact there's more room for optimization as the SetResourceFactory method has an overload that allows us to inject the body of the GetInstance and ReleaseInstance methods directly which makes the creation of the LightCoreResourceFactory obsolete and leads us to the following configuration instantiation:

var configuration = HttpHostConfiguration.Create()
                .SetResourceFactory((serviceType, instanceContext, request) 
                    => container.Resolve(serviceType), null);

Did you notice that we didn't really speak about the WCF Web API itself since the beginning of this post which simply highlights the fact that it does not get in way using this pattern -- well done.

Speaking of done: we've finished another hands on lab on the WCF Web API -- thanks for reading.

Next time we'll make it more RESTful and add some tests in BDD style.

Postings published on this series so far:

DotNetKicks-DE Image.aspx&bgcolor=3169AD&fgcolor=FFFFFF&border=000000&cbgcolor=D4E1ED&cfgcolor=000000)