Укажите службу Singleton в самообслуживании WCF
Я пишу приложение, которое предоставляет службу через WCF. Служба является самостоятельной (консольное приложение) и должна использовать экземпляр Singleton. Я пытаюсь выяснить, как указать singleton в конфигурации службы, не используя атрибуты в реализации службы. Можно ли указать singleton в коде без атрибута?
Спасибо,
Erick
Ответы
Ответ 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"/>