Using StructureMap with WCF Web API

by toni 20. October 2011 19:40

The following shows you how to use StructureMap as your IOC container with WCF Web API. You can find the full source code from github.

In your WebApiConfiguration you need to specify the functions which are used to create and release instances. For this example I have created custom configuration:

public class ApiConfiguration : WebApiConfiguration
{
    public ApiConfiguration()
    {
        this.CreateInstance = this.OnCreateInstance;
        this.ReleaseInstance = this.OnReleaseInstance;
    }
}

In the OnCreateInstance method we use the nested container to create the instance and save the container into custom extension. This is needed when we have to release the instance.

private object OnCreateInstance(Type type,
    InstanceContext instanceContext, 
    HttpRequestMessage message)
{
    Debug.WriteLine("Creating instance");

    // Using nested container will track all transient 
    // objects (e.g. non singleton, objects not scoped 
    // into httpcontext). When nested container is disposed
    // then all transient objects are also disposed.
    var nestedContainer = ObjectFactory.Container.GetNestedContainer();
    
    var extesion = new NestedContainerExtension(nestedContainer);
    instanceContext.Extensions.Add(extesion);

    var instance = nestedContainer.GetInstance(type);

    return instance;
}

The implementation for the extension is simple.

public class NestedContainerExtension : 
    IExtension<InstanceContext>, IDisposable
{
    private readonly IContainer container;

    public NestedContainerExtension(IContainer container)
    {
        this.container = container;
    }

    public void Attach(InstanceContext owner)
    {    
    }

    public void Detach(InstanceContext owner)
    {
        this.Dispose();
    }

    public void Dispose()
    {
        this.container.Dispose();
    }
}

All it does is keep reference to the nested container that was used to create the service instance. In the OnReleaseInstance we get the extension and dispose it which disposes the nested container.

private void OnReleaseInstance(
    InstanceContext instanceContext, 
    object instance)
{
    var extesion = 
        instanceContext.Extensions.Find<NestedContainerExtension>();
    extesion.Dispose();
}

The sample in github demonstrates what happens when you are using standard unit of work pattern. This means you have something like NHibernate’s SessionFactory that is created once. The SessionFactory is then used to create ISession per request. If you run the sample you’ll see following in the output window in Visual Studio.

Creating instance
SessionFactory e8fa70f2-2371-48de-b66b-98736f0f2128 created
SessionFactory e8fa70f2-2371-48de-b66b-98736f0f2128 opening session.
DatabaseSession c262a457-8109-4731-b0d8-9b5604a15289 created
ContactsApi 518a3d87-3557-44ca-9143-993b13c8e715 created and got session c262a457-8109-4731-b0d8-9b5604a15289
ContactsApi 518a3d87-3557-44ca-9143-993b13c8e715 Get() called
Releasing instance
NestedContainerExtension.Dispose called
DatabaseSession c262a457-8109-4731-b0d8-9b5604a15289 disposed
ContactsApi 518a3d87-3557-44ca-9143-993b13c8e715 Disposed

As you can see the SessionFactory is created (first request) and it is used to open session. Once the request has been served the session is disposed. If you send new request (e.g. refresh the web page) you’ll see following in the output window in Visual Studio:

Creating instance
SessionFactory e8fa70f2-2371-48de-b66b-98736f0f2128 opening session.
DatabaseSession 7a42e83c-e30e-47dd-a325-d0752ee74c00 created
ContactsApi d47063ca-9836-4076-8907-deb4a387864d created and got session 7a42e83c-e30e-47dd-a325-d0752ee74c00
ContactsApi d47063ca-9836-4076-8907-deb4a387864d Get() called
Releasing instance
NestedContainerExtension.Dispose called
DatabaseSession 7a42e83c-e30e-47dd-a325-d0752ee74c00 disposed
ContactsApi d47063ca-9836-4076-8907-deb4a387864d Disposed

Since the SessionFactory has already been created it is not recreated. New database session is created and disposed correctly.

Pingbacks and trackbacks (1)+

Comments are closed