Thursday, June 5, 2008

Unity, WCF and IIS

In a previous post, I showed how to integrate Unity with WCF when you are self-hosting a service. What's not clear is how to get IIS to use the Unity-enabled host when it starts hosting your service.

This is accomplished with a ServiceHostFactory. The @ServiceHost directive has an attribute named, curiously enough, Factory. This can be used to designate a class which will provide a configured ServiceHost. More on that in a moment. Let's see an example of a service that needs constructor-injection.

I've taken the default Service that Visual Studio 2008 gives you when you create a WCF Web Service, and added a SuffixProvider dependency that is satisfied in the constructor.



namespace WcfService1
{
public class Service1 : IService1
{
private ISuffixProvider provider;
public Service1(ISuffixProvider provider)
{
this.provider = provider;
}

public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}

public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite.BoolValue)
{
composite.StringValue += provider.GetSuffix();
}
return composite;
}
}
}

namespace WcfService1
{
public interface ISuffixProvider
{
string GetSuffix();
}
}


namespace WcfService1
{
public class MySuffixProvider : ISuffixProvider
{
#region ISuffixProvider Members

public string GetSuffix()
{
return "estericize";
}

#endregion
}
}



Using the UnityWCF project created in the previous post, I will create a factory that is derived from ServiceHostFactory, and configure a Unity container to supply a concrete implementation of ISuffixProvider. I have done this in code, most likely you will want to configure it from an XML file.



using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Microsoft.Practices.Unity;
using UnityWCF;

namespace WcfService1
{
public class UnityServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
UnityServiceHost host = new UnityServiceHost(serviceType, baseAddresses);
UnityContainer unity = new UnityContainer();
host.Container = unity;

//configure container
unity.RegisterType<ISuffixProvider,MySuffixProvider>();

return host;
}
}
}


Finally, edit the Service1.svc file to reference the factory class:

<%@ ServiceHost Language="C#"
Debug="true"
Factory="WcfService1.UnityServiceHostFactory"
Service="WcfService1.Service1"
CodeBehind="Service1.svc.cs" %>

6 comments:

shmulsh said...

hi.
I understand you can inject all the registered types to the class in the service or business layers. But how can you resolve types or instances with unity(the container) in the business classes?
unity is defined private.

Ray Henry said...

Hi shmulsh,

I'm not clear on what you are trying to accomplish.

Your business classes should not be using Unity to resolve types.

In the case of this post, I have a WCF service. I have configured Unity and when a WCF service is instantiated, the dependencies will be injected. If your WCF service depends on a business class, then it too will be instantiated along with its dependencies and injected into the WCF service.

It's important not to write your components to depend on a particular container implementation (like unity). References to the container should be isolated to a particular part of the infrastructure as they are here in this post. The WCF service and everything that it depends upon should have no knowledge of the DI container.

Maybe you could provide an example of what you are trying to do. It's possible that I misunderstand you.

Julian Maughan said...

If I'm not mistaken, your ServiceHostFactory implementation will create a new instance of UnityContainer for each service. Wouldn't it be better to instantiate and configure the container once for the whole application? Please have a look at my blog for a possible solution :)

Dan said...

Ray,

Why should your business classes not use an IoC container?

If you use a model with business objects that only apply business rules and rely on a data layer for data access, it seems to me that the an IoC container would be very useful to maintain this seperation of concerns and loosely coupled tiers. I'm still fairly new to IoC though. So, if I'm wrong, please enlighten me.

Thanks,
Dan

Ray Henry said...

@Julian:

You are correct; if you would like to have a single container for all your services using the custom ServiceHostFactory, then your solution is a workable one.

Ray Henry said...

@Dan:

Why not let the WCF service be instantiated with all the business services (supplied by the Unity container) that will be needed?

Let's differentiate between business services (logic) and business data (model). I assumed shmulsh was talking about the business data, which ideally should not depend on a container. If he (and/or you) are referring to business services or logic, then I feel that you should write them with DI (constructor-injection preferably) to get all their dependencies and since the WCF service will depend on these business services then Unity can inject them into the WCF service with all dependencies resolved.

Do you have a specific use case that I can try to address?