Подтвердить что ты не робот

Укажите службу Singleton в самообслуживании WCF

Я пишу приложение, которое предоставляет службу через WCF. Служба является самостоятельной (консольное приложение) и должна использовать экземпляр Singleton. Я пытаюсь выяснить, как указать singleton в конфигурации службы, не используя атрибуты в реализации службы. Можно ли указать singleton в коде без атрибута?

Спасибо, Erick

4b9b3361

Ответ 1

Вы можете передать экземпляр службы в конструктор ServiceHost вместо передачи типа. В этом случае ваш переданный экземпляр будет использоваться как singleton.

Edit:

Мое прежнее решение не работает. Предоставление экземпляра конструктору ServiceHost по-прежнему требует ServiceBehaviorAttribute с помощью InstanceContextMode.Single. Но это должно работать:

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

ServiceBehaviorAttribute включен, даже если вы не указали его, поэтому вам просто нужно его получить и изменить значение по умолчанию.

Ответ 2

Если вы хотите переместить это в web.config или app.config, вы можете сделать это с помощью пользовательских BehaviorExtensionElement и IServiceBehavior:

IServiceBehavior будет фактически анализировать значение из config в перечисление и устанавливать его (после ответа @Ladislav):

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;
    }
}

Элемент расширения позволяет вытащить его из конфига и передать его в 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;
        }
    }
}

И вы можете зарегистрировать его в своей конфигурации и использовать его:

<extensions>
  <behaviorExtensions>
    <add name="instanceContext" type="FULLY QUALFIED NAME TO CLASS"/>
  </behaviorExtensions>
</extensions>
...
  <serviceBehaviors>
    <behavior name="Default">
      <instanceContext contextMode="Single"/>