ArielBH
ArielBH

Reputation: 2001

WCF on IIS: Passing data from a ServiceHostFactory to the Service instances

I am having a WCF application hosted on IIS. I am initializing an IoC container in a custom ServiceHostFactory.

Basically what I would like is to be able to "inject" that IoC Container to each Service instance created within the scope of that ServiceHost.

How would you accomplish that?

Ariel

Upvotes: 1

Views: 939

Answers (1)

tucaz
tucaz

Reputation: 6684

Like you said you will need a custom ServiceHostFactory that should be used in order to create your services. Something like this:

public class SessionPerCallServiceHostFactory : ServiceHostFactory
{
    public SessionPerCallServiceHostFactory()
    {
    }

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

You will also need a ServiceHost responsible for creating the necessary service:

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

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

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

}

With a custom implementation of IServiceBehavior that will be able to provider the InstanceProvider used to create the service instances:

public class SessionPerCallServiceBehavior : 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 SessionPerCallInstanceProvider(serviceDescription.ServiceType);
                }
            }
        }
    }

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

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

}

And finally the instance provider that will allow you to use the IoC to inject whatever you want in the requested service instance:

public class SessionPerCallInstanceProvider : IInstanceProvider
{
    private readonly Type _serviceType;

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

    public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
    {
        //I'm creating it without any tricks but you could use your IoC container here
        return Activator.CreateInstance(_serviceType);
    }

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

    public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
    {

    }
}

Hope it helps!

Upvotes: 2

Related Questions