Specify a Singleton service in a WCF self hosted service

試著忘記壹切 提交于 2019-11-28 12:01:19

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.

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"/>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!