2
votes

I'm trying to see if this is possible. I want to resolve the WCF service class from castle windsor via a factory class. The WCF service is hosted in IIS and so far I've only been getting a 404 when I try to call the service when using the factory. Here is my registration code:

container.AddFacility<WcfFacility>();

container.Register(Component.For<IServiceFactory>() 
                            .ImplementedBy<ServiceFactory>()
                            .LifestyleSingleton());

container.Register(Component.For<IFooService>()
                            .UsingFactoryMethod((kernel, context)
                                    => kernel.Resolve<IServiceFactory>()
                                                     .CreateService(context.RequestedType))                                     
                            .Named("FooService")
                            .LifestylePerWcfOperation());

Here is my factory class:

public class ServiceFactory : IServiceFactory
{
    public IFooService CreateService(Type forType)
    {
        IFooService createdType = null;

        if (forType == typeof(IFooService))
            createdType = new FooService();

        return createdType;
    }
}

I have tried doing a strait .ImplementedBy<FooService>() and that works fine. It's only when I want to do it via a factory that I have a problem. Is this possible, meaning I'm missing something, or is it not possible?

(I know that the code shown is pretty simple, I am only testing if its possible before fully implementing my factory code)

1
When I implemented this, It was a lot less simple than I think it should have been - I think I had to make three or four more classes, roughly as described here (just replace unity conventions with windsor): i-avington.com/Posts/Post/usng-unity-with-a-wcf-serviceeouw0o83hf
I was afraid that I might have to write my own ServiceHostFactory. I decided on asking this question first.Chris
Yeah, I tried really hard not to have to do that, but, unless something has changed, there doesn't seem to be any way around it. Sorry :-/eouw0o83hf
Are you using .svc files? Are you using Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory" in them?Polly Shaw
Yes to both of those questionsChris

1 Answers

0
votes

you don't have to create a custom ServiceHost to do this, though you're right this is harder than it should be. The article that eouw0o83hf references first talks about an IInstanceProvider. That's the key, but you can wire it up using and WCF ServiceBehavior as well instead of a customer ServiceHost. I'm not sure what your FactoryMethod has to do with this - it sounds like it's a general wire up issue... or I'm not understanding your problem. I'll show below how I do the wire up without the ServiceHost and hopefully that fixes your problem.

First create a class that implements IInstanceProvider - mine below calls out to my ObjectResolver class with wraps Windsor. I'll leave that out for brevity.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

public class ObjectResolverInstanceProvider : IInstanceProvider
{
    private readonly Type _serviceType;

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

    public object GetInstance(InstanceContext instanceContext)
    {
        return ObjectResolver.Resolve(_serviceType);
    }

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

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        ObjectResolver.Release(instance);
    }
}

Then create a service behavior that assigns your instance provider to each endpoint's DispatchRuntime's InstanceProvider:

using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

public class ConstructWithObjectResolverAttribute : Attribute, 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 ObjectResolverInstanceProvider(serviceDescription.ServiceType);
                }
            }
        }
    }

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

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

Next apply the service attribute to your service implementation... note you could do this in config if you wanted too, but I prefer applying it via an attribute like so:

   [ConstructWithObjectResolver]
   [ServiceBehavior(Namespace="YourNamespace")]
   public class FooService : IFooService {}