locked
Session based service and instance context - help! RRS feed

  • Question

  • Hi,

    I have a service which i am trying to get running in InstanceMode.PerSession but have a few issues which are blocking me. My problem is my service implementation 'GatewayService' (below) has some private variables which I am setting via a custom contructor.


    [ServiceBehavior(
            IncludeExceptionDetailInFaults=true,
    	 InstanceContextMode=InstanceContextMode.PerSession,
            ConcurrencyMode = ConcurrencyMode.Single
        )]
    	public class GatewayService : IGatewayService
           {
    		// private fields...
    		// custom constructor to populate private fields...
                    // IGatewayService methods...
    	}


    IGatewayServer service contract:

    [ServiceContract(SessionMode=SessionMode.Required)]
    public interface IGatewayService
    {
    [OperationContract(IsInitiating = false, IsTerminating = false, IsOneWay = true)]
            void Log(string value);
    
    [OperationContract(IsInitiating = true, IsTerminating = false)]
            string Challenge(string value);
    
    [OperationContract(IsInitiating = false, IsTerminating = false)]
            string GetValue(string value);
    
    [OperationContract(IsInitiating = false, IsTerminating = false, IsOneWay = true)]
            void SetValue(string value);
    
    [OperationContract(IsInitiating = false, IsTerminating = true, IsOneWay = true)]
            void Close();
    }

    Service Startup:

    _service = new GatewayService(avariable, anothervariable);
    _host = new ServiceHost(_service);
    _host.Open(); 

    Its quite clear im doing something totally wrong here, but just can't work it out. I know I can start the servicehost using a type also, but then how do I pass my variable to my service class?

    Confused, any help very much appreciated.
    Friday, January 22, 2010 3:17 PM

Answers

  • The problem is you are using the singleton form of the ServiceHost constructor. For PerSession there is one instace craeted per session so the WCF infrastructure needs to be in control of getting new instances. However, there is an extensibility point called IInstanceProvider http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iinstanceprovider.aspx that allows you to take control of the actual instance creation which would allow you to use a parameterized constructor
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Twitter: richardblewett
    Friday, January 22, 2010 3:27 PM
  • Thanks for the response, I have followed it down this road and seems to be working nicely... heres a copy of my changes for anyone else stuck on this:

    public class GatewayServiceHost : ServiceHost
        {
            public GatewayServiceHost(CustomParam p1, CustomParam p2) // <!-- add you own custom objects
    : base(typeof(GatewayService)) { foreach (var cd in this.ImplementedContracts.Values) { cd.Behaviors.Add(new GatewayInstancingBehavior(p1, p2)); } } } public class GatewayInstancingBehavior : IInstanceProvider, IContractBehavior { private readonly CustomParam _param1; private readonly CustomParam _param2; GatewayService service = null; public GatewayInstancingBehavior(CustomParam p1, CustomParam p2) { Console.WriteLine("The non-default constructor has been called."); _param1 = p1; _param2 = p2; this.service = new GatewayService(p1, p2); } #region IInstanceProvider Members public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message) { Console.WriteLine("GetInstance is called:"); return new GatewayService(_param1, _param2);
    } public object GetInstance(InstanceContext instanceContext) { Console.WriteLine("GetInstance is called:"); return new GatewayService(_param1, _param2); } public void ReleaseInstance(InstanceContext instanceContext, object instance) { Console.WriteLine("ReleaseInstance is called. The SingletonBehaviorAttribute never releases."); instanceContext.ReleaseServiceInstance(); } #endregion #region IContractBehavior Members public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection parameters) { return; } public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { return; } public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch) { dispatch.InstanceProvider = this; } public void Validate(ContractDescription description, ServiceEndpoint endpoint) { return; } #endregion }
    (Taken from: http://blogs.msdn.com/ploeh/archive/2008/06/27/modifying-behavior-of-wcf-free-service-implementations.aspx)
    • Marked as answer by MutablePro Friday, January 22, 2010 6:17 PM
    Friday, January 22, 2010 4:36 PM

All replies

  • The problem is you are using the singleton form of the ServiceHost constructor. For PerSession there is one instace craeted per session so the WCF infrastructure needs to be in control of getting new instances. However, there is an extensibility point called IInstanceProvider http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iinstanceprovider.aspx that allows you to take control of the actual instance creation which would allow you to use a parameterized constructor
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Twitter: richardblewett
    Friday, January 22, 2010 3:27 PM
  • Thanks for the response, I have followed it down this road and seems to be working nicely... heres a copy of my changes for anyone else stuck on this:

    public class GatewayServiceHost : ServiceHost
        {
            public GatewayServiceHost(CustomParam p1, CustomParam p2) // <!-- add you own custom objects
    : base(typeof(GatewayService)) { foreach (var cd in this.ImplementedContracts.Values) { cd.Behaviors.Add(new GatewayInstancingBehavior(p1, p2)); } } } public class GatewayInstancingBehavior : IInstanceProvider, IContractBehavior { private readonly CustomParam _param1; private readonly CustomParam _param2; GatewayService service = null; public GatewayInstancingBehavior(CustomParam p1, CustomParam p2) { Console.WriteLine("The non-default constructor has been called."); _param1 = p1; _param2 = p2; this.service = new GatewayService(p1, p2); } #region IInstanceProvider Members public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message) { Console.WriteLine("GetInstance is called:"); return new GatewayService(_param1, _param2);
    } public object GetInstance(InstanceContext instanceContext) { Console.WriteLine("GetInstance is called:"); return new GatewayService(_param1, _param2); } public void ReleaseInstance(InstanceContext instanceContext, object instance) { Console.WriteLine("ReleaseInstance is called. The SingletonBehaviorAttribute never releases."); instanceContext.ReleaseServiceInstance(); } #endregion #region IContractBehavior Members public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection parameters) { return; } public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { return; } public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch) { dispatch.InstanceProvider = this; } public void Validate(ContractDescription description, ServiceEndpoint endpoint) { return; } #endregion }
    (Taken from: http://blogs.msdn.com/ploeh/archive/2008/06/27/modifying-behavior-of-wcf-free-service-implementations.aspx)
    • Marked as answer by MutablePro Friday, January 22, 2010 6:17 PM
    Friday, January 22, 2010 4:36 PM