tags:

views:

844

answers:

2

I am just getting into MEF and I have come across a problem that I cannot resolve. I have a windows service that is reading in my DLLs (via MEF) and each DLL is a WCF Service Host. When I run my windows service and read in the DLLs everything runs fine, except that whenever one of the WCF DLLs get any "activity" then they reinstantiate and then process the data coming in. I need them to just instantiate once at the beginning. Is this possible?

+2  A: 

You can handle this by implementing an IServiceBehavior and an IInstanceProvider, registering my implmentation of IServiceBehavior in OnStart, and having IInstanceProvider manage object lifetime for you. In particular, you can use an inversion of control container that serves up the same instance of your service type on each request (i.e., singleton-like behavior without being a singleton).

public partial class MyServiceHost : ServiceBase {
    // details elided

    protected override void OnStart(string[] args) {
            this.Host = new ServiceHost(typeof(MySerivce));
            this.Host.Description.Behaviors.Add(new MyServiceBehavior());
            this.Host.Open();
    }
}

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

    public void ApplyDispatchBehavior(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase) {
            IIoCContainer container = new IocContainer();
            foreach (var cdBase in serviceHostBase.ChannelDispatchers) {
                ChannelDispatcher cd = cdBase as ChannelDispatcher;
                if (cd != null) {
                    foreach (EndpointDispatcher ed in cd.Endpoints) {
                        ed.DispatchRuntime.InstanceProvider = new MyInstanceProvider(
                            container,
                            serviceDescription.ServiceType
                        );
                    }
                }
            }
        }

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

public class MyInstanceProvider : IInstanceProvider {
    readonly IIocContainer _container;
    readonly Type _serviceType;

    public InstanceProvider(IIoCContainer container, Type serviceType) {
        _container = container;
        _serviceType = serviceType;
    }

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

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

    public void ReleaseInstance(InstanceContext instanceContext, object instance) { }       
}
Jason
I guess could you give me a small sample or maybe go into more detail. I am by no means an export in MEF or WCF.
Travyguy9
I added a barebones implementation of what I'm talking about. The key is the inversion of control container that manages object lifetime.
Jason
Which assembly is the IIocContainer located?
Travyguy9
That's for you to decide. `IIoCContainer` is made up but you can use any inversion of control container (e.g., Castle Windsor, StructureMap or Unity).
Jason
I did some looking around and I noticed that my WCF Service that gets read in by my windows service is on the AppDomain ID of 1 and then the WCF Service that gets notified of data coming in has an AppDomain ID of 2. Does the solution you gave me (which is on the WindowService I think) guarantee that the I will always use the one with the AppDomain of 1?
Travyguy9
+1  A: 

WCF services default to a per call instance mode. This means that a new instance of your WCF service is instantiated for each incoming method invocation. It sounds like what you're wanting is a singleton instance mode, but you really want to avoid this if scability is an issue.

The way I've gotten around this is to use the per call instance mode, but have a static data store behind the scenes that I synchronize access to. This at least allows clients to connect, even if they have to block momentarily while the data store is in use once the connection is established.

Refer to the MSDN help on System.ServiceModel.InstanceContextMode for more details.

Matt Davis