我正在编写一款通过WCF公开服务的应用程序。该服务是自承载的(控制台应用程序),需要使用单例实例。我正试图弄清楚如何在服务配置中指定单例,而不使用服务实现上的属性。是否可能在代码中指定单例而不使用属性?
谢谢, Erick
我正在编写一款通过WCF公开服务的应用程序。该服务是自承载的(控制台应用程序),需要使用单例实例。我正试图弄清楚如何在服务配置中指定单例,而不使用服务实现上的属性。是否可能在代码中指定单例而不使用属性?
谢谢, Erick
ServiceHost
构造函数,而不是传递类型。在这种情况下,您传递的实例将被用作单例。
编辑:
我的前一种解决方案不起作用。向ServiceHost
构造函数提供实例仍然需要ServiceBehaviorAttribute
和InstanceContextMode.Single
。但是这样应该行得通:
var host = new ServiceHost(typeof(Service));
var behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
host.Open();
即使您没有指定,ServiceBehaviorAttribute
也会被包含,因此您只需要获取它并更改默认值。
web.config
或app.config
中,可以使用自定义的BehaviorExtensionElement
和IServiceBehavior
来实现:
IServiceBehavior
将从配置中解析值并将其设置为枚举(遵循@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"/>
InstanceContextMode
设置为PerCall
,而这种方法也适用于此。 - Dan