Integrating StructureMap with WCF

When developing with an IoC container like StructureMap, eventually some place in your code you will need to call the registry to instantiate your classes with their dependencies.  With StructureMap, this means a call to ObjectFactory.GetInstance.  Ideally, we’d like to limit the number of places the registry is called, so that we don’t have a lot of StructureMap concerns sprinkled throughout our application.

Suppose we have the following WCF service:

public class CustomerSearchService : ICustomerSearchService
{
    private readonly ICustomerRepository _customerRepository;
    private readonly ICustomerSummaryMapper _customerSummaryMapper;

    public CustomerSearchService(ICustomerRepository customerRepository, ICustomerSummaryMapper customerSummaryMapper)
    {
        _customerRepository = customerRepository;
        _customerSummaryMapper = customerSummaryMapper;
    }

    public CustomerSearchResult FindCustomerByName(string fullName)
    {
        Customer customer = _customerRepository.FindCustomerByName(fullName);

        if (customer == null)
        {
            return new CustomerSearchResult
                       {
                           IsSuccessful = false,
                           FailureReasons = new[] {"Customer not found."}
                       };
        }

        CustomerSummary summary = _customerSummaryMapper.MapFrom(customer);

        return  new CustomerSearchResult {IsSuccessful = true, Result = summary};
    }
}

Nothing too exciting, just a search service that returns customer summary information from a name search.  Now, if we just try to use this service as is, we get a fun exception:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

That makes sense, as WCF is in charge of instantiating my service class (CustomerSearchService), but it only knows how to call a no-args constructor.  For a quick fix, we can add this constructor:

public CustomerSearchService()
    : this(ObjectFactory.GetInstance<ICustomerRepository>(), 
        ObjectFactory.GetInstance<ICustomerSummaryMapper>())
{
}

Each of our WCF services would need to the same thing, have a bunch of ObjectFactory calls to set up the dependencies appropriately.  But we can find a better way, and have all of our services wired up automatically, with only one call to StructureMap in the entire application.  To do this, we’ll need to plug in to a few WCF extension points to make it happen.

A custom instance provider

WCF provides an interface just for this purpose, IInstanceProvider, that allows us to create custom instantiation behavior.  This interface has basically two methods:

  • CreateInstance – needs to return the right service
  • ReleaseInstance – if we have some custom cleanup to do

Just creating the IInstanceProvider isn’t enough, we’ll have to tell WCF to use our instance provider, instead of its own default instance provider.  This requires a custom endpoint behavior.  We can’t configure the instance provider directly, through configuration or other means.  Instead, we’ll use a custom service behavior through the IServiceBehavior interface.  Here’s the implementation of our custom service behavior:

public class StructureMapServiceBehavior : IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
        {
            ChannelDispatcher cd = cdb as ChannelDispatcher;
            if (cd != null)
            {
                foreach (EndpointDispatcher ed in cd.Endpoints)
                {
                    ed.DispatchRuntime.InstanceProvider = 
                        new StructureMapInstanceProvider(serviceDescription.ServiceType);
                }
            }
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

For all of the endpoints in all of the channels, we need to give WCF our custom instance provider.  Also, since StructureMap needs to know what type to create, we have to pass that information along to our instance provider.  This comes from the ServiceDescription passed in above.

With our service behavior done, let’s create the actual instance provider, which will call StructureMap:

public class StructureMapInstanceProvider : IInstanceProvider
{
    private readonly Type _serviceType;

    public StructureMapInstanceProvider(Type serviceType)
    {
        _serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return ObjectFactory.GetInstance(_serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
    }
}

Pretty straightforward, we just capture the service type (passed in from our service behavior earlier), then use ObjectFactory to create an instance of that service when asked.  There’s no information on the InstanceContext about the service type, or we could have just used it instead.

Now that we have our IInstanceProvider and IServiceBehavior, it’s time to hook up this new service behavior to the rest of WCF.  We have a few choices:

  • Attributes
  • Custom service host
  • Configuration

With attributes, we’d decorate all of our services with something like [StructureMapServiceBehavior] or something similar, so that WCF would know to attach our IServiceBehavior to the ServiceDescription behaviors.  Attributes are okay, but again, we’d have to put something on all of our services.  Since the whole point of this exercise was to reduce the footprint, let’s go the custom service host route.

As for configuration, I can’t stand XML, so let’s just pretend that one doesn’t exist.

A custom service host

By going the custom ServiceHost route, we’ll just need to plug in to the right event to add our custom service behavior to the mix.  Here’s what we wind up creating:

public class StructureMapServiceHost : ServiceHost
{
    public StructureMapServiceHost()
    {
    }

    public StructureMapServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
    }

    protected override void OnOpening()
    {
        Description.Behaviors.Add(new StructureMapServiceBehavior());
        base.OnOpening();
    }
}

Nothing too exciting, we just add our custom service behavior to the ServiceDescription Behaviors collection, right before the service host is opened in the OnOpening method.

Next, to plug in our custom service host, we’ll need a custom service host factory:

public class StructureMapServiceHostFactory : ServiceHostFactory
{
    public StructureMapServiceHostFactory()
    {
        StructureMapConfiguration
            .ScanAssemblies()
            .IncludeTheCallingAssembly()
            .With<DefaultConventionScanner>();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new StructureMapServiceHost(serviceType, baseAddresses);
    }
}

The overridden method makes sense, override the CreateServiceHost to…create our custom service host.  However, there’s quite a bit going on in the constructor.

At this point, it will start to matter how you’d like StructureMap to be configured:

  • Attributes
  • XML config
  • Code

I’m liking the code way, as we don’t have to have crazy XML or a bunch of attributes everywhere.  Which way you configure is up to you, but if you go the code route, you’ll need to put the StructureMap configuration in the constructor here.

Finally, we’ll need to configure our WCF service to use this service host factory.  I’m using IIS to host, so I’ll just need to change my .svc file:

<%@ ServiceHost Language="C#" Debug="true" 
    Service="SMExample.Wcf.CustomerSearchService" 
    Factory="SMExample.Wcf.StructureMapServiceHostFactory" %>

Other hosting solutions will use different ways of using the custom service host factory.

Recap

We wanted to use StructureMap with WCF, but this initially presented us with some problems.  WCF requires a no-args constructor, which means we’ll have to use a lot of ObjectFactory.GetInstance calls on every service implementation.

Instead, we can use WCF extension points to use StructureMap to create the service for us, without needing that messy constructor.  We created two extensions:

  • IInstanceProvider
  • IServiceBehavior

Once we had our custom instance provider and service behavior, we needed to decide how our custom service behavior would get attached to our service.  We chose the custom service host route, which meant two more custom WCF implementations:

  • ServiceHost
  • ServiceHostFactory

The ServiceHostFactory implementation forced us to decide how our dependencies should be configured in StructureMap, and we went the code route.  Finally, we configured our service host in IIS to use the right service host factory.

With all this in place, none of our service classes nor their implementations need to know anything about StructureMap, allowing their design to grow and change outside of WCF construction concerns.  We also reduced the footprint of StructureMap in our application, where we now had exactly one call to the StructureMap infrastructure, ObjectFactory.GetInstance.  With this one place StructureMap is used, it will be easier to swap out IoC container implementations (just kidding, Jeremy).

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in StructureMap, Tools, WCF. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    Awesome post! Now, how do you feel about getting that WCF goodness into the next StructureMap release?

  • http://orand.blogspot.com Oran
  • Darren

    Great post.

    What version of StructureMap is this post referencing? It would help readers if all bloggers would add the versions of tools they are working with in their posts.

    FYI, part of the text in this post is being cut off on the right side of page. I had to make the browser well over 1600 pixels wide (in IE 7 and FF 2) before I could read all the words.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Oran

    Yeah, your example, plus a Unity and Windsor example were combined for this one.

    @Darren

    It’s SM 2.4.9. As for the code, sorry about that! I’m so used to reading in a feed reader, I forget to check in an actual browser. I’ll make a note of that for future posts. Thanks!

  • http://initializecomponent.blogspot.com Ray Henry

    Hey y’all,

    For Unity/WCF integration see:
    http://initializecomponent.blogspot.com/2008/06/integrating-unity-with-wcf.html

    Thanks!

  • Brian Walk

    Great Post! I have implemented all of the changes to my app but I am having an issue setting up the default instance in WCF. I have seen posts that setup the interface to a concrete class in code(e.g. a Registry), but I must be missing something when implementing this in WCF, how do you do this in a WCF app?

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Brian

    Great question! Might I suggest putting this question on the StructureMap mailing list?

    http://groups.google.com/group/structuremap-users

    We’re trying to consolidate the questions and such into one search-able place.

  • Brian Walk
  • FrankM

    The new 2.5 ObjectFactory.Initializa() syntax doesn’t work here. It seems ServiceHostFactory doesn’t support Lambda expression.

    Could you look at it?

  • FrankM

    Sorry, I have played web.config for a while, this compile error magically went away. It was my machine problem. Nothing to do with LinQ.

  • http://blog.ingenuitynow.net Andy

    This is great. I was really worried about implementing this but thanks to your help it was very easy. I did make one change, however. I’m using a Bootstrapper class as follows:

    public class Bootstrapper : IBootstrapper
    {
    public virtual void BootstrapStructureMap()
    {
    ObjectFactory.Initialize(x =>
    {
    x.ForRequestedType().TheDefaultIsConcreteType();
    x.ForRequestedType().TheDefaultIsConcreteType();
    });
    }

    public static void Bootstrap()
    {
    new Bootstrapper().BootstrapStructureMap();
    }
    }

    To use the Bootstrapper, just call it in from the constructor of StructureMapServiceHostFactory:
    public class StructureMapServiceHostFactory : ServiceHostFactory
    {
    public StructureMapServiceHostFactory()
    {
    Bootstrapper.Bootstrap();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
    return new StructureMapServiceHost(serviceType, baseAddresses);
    }
    }

  • Tom Schreck

    I’ve created all of the code from the examples outlined in the blog and it builds. I have my SearchService.svc file created that looks like this:

    < %@ ServiceHost Language="C#" Debug="true"
    Service="WcfStructureMap.CustomerSearchService"
    Factory="WcfStructureMap.StructureMapServiceHostFactory" %>

    I run the service by hitting F5 and I still get the missing default parameterless constructor error message. I suspect I’m missing a configuration setting in app.config. How do I wire up the svc file? I created the file, but not sure how it gets wired into the WCF service.

    Is it possible for you to post example code please?

  • Tom Schreck

    By “post example code” in my previous comment, i meant do you have a download available with example code implementing how StructureMap and Wcf please? Sorry for the confusion.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Tom

    So…this post is out of date, check this post out with complete code:

    http://andreasohlund.blogspot.com/2009/04/unitofwork-in-wcf-using-structuremap.html

  • http://www.sgriffinusa.com/ Scott Griffin

    Thanks for the post. I was able to expand on it to get StructureMap to load for every service without adding the Factory to each service class. http://www.sgriffinusa.com/2011/02/setting-up-wcf-to-use-structuremap.html

  • IG

    Excellent.

    Thanks a lot.

  • Lehlogonolo Masekela

    this is an excellent post. Thanks Jimmy you The best.

  • http://twitter.com/jayrubdub Jeremy W

    Thanks for this walk through, really helpful

  • http://twitter.com/jayrubdub Jeremy W

    This is working great, just wondering if this is still how you do it 3 years later?

    • Anonymous

      No idea – this was the last time I actually built a WCF service! Try posting this question on the SM user group – I know there have been updates to my example.

      • Vasilio Ruzanni

        Jimmy,
        Any comments on why no more WCF?

        • Anonymous

          I don’t need it, there are simpler solutions that require less code and less configuration, or are more stable/reliable/durable.

          Also, no one’s asked me to build one. If someone required a SOAP endpoint, then yeah, I’d go that route.

          • Vasilio Ruzanni

            Yep, thanks, exactly what I expected. I think exactly the same way. We have ServiceStack and Protocol Buffers these days.

            Btw, I’d prefer ServiceStack even if I ever need the SOAP endpoint.

          • Anonymous

            Ha, never heard of ServiceStack, thanks for pointing it out!

          • http://rollersmb.myopenid.com/ RollerSMB

            Does ServiceStack even work with Structuremap?  From what I can see, it doesn’t seem to, seems to be pretty linear.

  • http://twitter.com/randomcodenz Neal Blomfield

    Great post, allowed me to get almost all the way to StructureMap + WCF.

    As this post still gets a lot of airtime it may be work adding a couple of things to it.
    1. If the ServiceBehaviourAttribute.InstanceContextMode is set to InstanceContextMode.SingleInstance then the IInstanceProvider is bypassed completely. ServiceBehaviourAttribute.InstanceContextMode controls the lifecycle of the service and therefore should probably be set to PerCall – servicew lifecycle should be delegated to the container.
    2. For some unknown reason, when using the WCF REST stuff, you cannot add the StructureMapBehaviour programmatically. I have used a behaviour extension attribute and some xml config (yes I shed many tears) to add the behaviour, but it may be possible with attributes.

    Thanks again for documenting this – definitely helped me on the way to WCF + SM.

    • EtherZa

      When using a singleton instance, replace the StructureMapServiceHost constructor with:

      public StructureMapServiceHost(Object singletonInstance, params Uri[] baseAddress)
      : base(singletonInstance, baseAddress)
      {
      }

  • Kekerain2011
  • Pingback: question about chapter 6... (adaptation)

  • Bas Hamer

    Thanks; I used this code as is and it worked great; one thing to watch out for is that out have to specify the DLL it came from in the .svc file.

    I used it in http://willbe.codeplex.com/ ; a simple compile time AOP framework

  • Jason Still

    I know this is old, but it helped me a ton and worked *almost* flawlessly. The only change I had to make was in the StructureMapServiceHostFactory constructor. StructureMapConfiguration isn’t a thing anymore, but the below code worked as the contents of the constructor. Hopefully this will save the next person who comes along a few minutes of confusion.

    ObjectFactory.Initialize(x =>
    {
    x.Scan(scan =>
    {
    scan.TheCallingAssembly();
    scan.WithDefaultConventions();
    });
    });

    • jbogard

      Ha! Nice.

  • Adrian Hofman

    Hi there,

    First off, thanks a heap for this, it was a great help to me.

    I know it’s quite old now, but there is a subtle bug in the StructureMapServiceBehavior.ApplyDispatchBehavior method – it disregards any existing InstanceProvider that is attached to the EndpointDispatcher.

    This was a problem for us when we tried to add WCF WS-Discovery to our services – the discovery behaviors add their own InstanceProvider implementation to their own Endpoints. We were coming along with our custom IOC InstanceProvider and stomping it over the top of the discovery InstanceProvider – and the discoverability broke :)

    We fixed this simply by checking for null first – i.e., only provide an IOC InstanceProvider when the existing one was null.

    Thanks again :)

  • Pingback: My recipe for WCF part 3 – Rolling your own integration with an IoC | Polly Shaw's Blog

  • ZacH

    What’s with the css on the code samples? Is there a browser/version where you can actually see the code without copying/pasting it into something?

    • jbogard

      So unfortunately this is a really old post before we used Gist plugins. I don’t have an easy way to convert it, sorry!

      • ZacH

        Can still get at the code via aforementioned copying/pasting. The content is still very good — I don’t mean to troll the css.

        I’ve just inherited a WCF service using StructureMap, creating my first opportunity to work with StructureMap. I’ve found this post very useful in understanding what I have. I just wanted to point out one thing:

        Littered throughout my interitance’s code are classes that look like this:

        public CustomerSearchService()
        : this(ObjectFactory.GetInstance(),
        ObjectFactory.GetInstance())
        {
        }

        And from recent reading of the StructureMap documentation, the deeper, egregious error stands out. The class is now coupled to the DI tool! (which sort of defeats the purpose of using a DI in the first place, doesn’t it? http://docs.structuremap.net/AutoWiring.htm )

        Thanks again for providing a way to use StructureMap’s auto wiring specifically with WCF and avoid this error.