Specify a Singleton service in a WCF self hosted service
Asked Answered
R

2

13

I am writing an application that exposes a service via WCF. The service is self-hosted (console app) and needs to use a Singleton instance. I am trying to figure out how to specify singleton in the service configuration without using attributes on the service implementation. Is it possible to specify singleton in code without an attribute?

Thanks, Erick

Rumba answered 20/3, 2011 at 23:10 Comment(0)
A
22

You can pass instance of the service to the ServiceHost constructor instead of passing a type. In such case your passed instance will be used as singleton.

Edit:

My former solution doesn't work. Providing instance to ServiceHost constructor still demands ServiceBehaviorAttribute with InstanceContextMode.Single. But this one should work:

var host = new ServiceHost(typeof(Service));
var behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
host.Open();

ServiceBehaviorAttribute is included even if you don't specify it so you just need to get it and change default value.

Ablate answered 20/3, 2011 at 23:20 Comment(2)
I am new to WCF and I have a WCF service which I want to control with configuration instead of metadata on class. Could you please provide details of your solution.Rubious
I needed to force the InstanceContextMode to PerCall, and this method works for that as well.Endamoeba
S
0

If you want to move this into web.config or app.config, you could do so with a custom BehaviorExtensionElement and IServiceBehavior:

The IServiceBehavior will actually parse the value from config into the enum and set it (following @Ladislav's answer):

public class InstanceContextServiceBehavior : IServiceBehavior
{
    InstanceContextMode _contextMode = default(InstanceContextMode);

    public InstanceContextServiceBehavior(string contextMode)
    {
        if (!string.IsNullOrWhiteSpace(contextMode))
        {
            InstanceContextMode mode;

            if (Enum.TryParse(contextMode, true, out mode))
            {
                _contextMode = mode;
            }
            else
            {
                throw new ArgumentException($"'{contextMode}' Could not be parsed as a valid InstanceContextMode; allowed values are 'PerSession', 'PerCall', 'Single'", "contextMode");
            }
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        var behavior = serviceDescription.Behaviors.Find<ServiceBehaviorAttribute>();
        behavior.InstanceContextMode = _contextMode;
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        return;
    }

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

The extension element allows you to pull it from config and pass it to the IServiceBehavior:

public class InstanceContextExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get
        {
            return typeof(InstanceContextServiceBehavior);
        }
    }

    protected override object CreateBehavior()
    {
        return new InstanceContextServiceBehavior(ContextMode);
    }

    const object contextMode = null;

    [ConfigurationProperty(nameof(contextMode))]
    public string ContextMode
    {
        get
        {
            return (string)base[nameof(contextMode)];
        }
        set
        {
            base[nameof(contextMode)] = value;
        }
    }
}

And you can then register it in your config and use it:

<extensions>
  <behaviorExtensions>
    <add name="instanceContext" type="FULLY QUALFIED NAME TO CLASS"/>
  </behaviorExtensions>
</extensions>
...
  <serviceBehaviors>
    <behavior name="Default">
      <instanceContext contextMode="Single"/>
Shebat answered 21/6, 2016 at 14:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.