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:
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.
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.
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 :)
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
@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.
@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?
Post a Comment