为什么 InstanceContextMode.Single 不工作?
Why isn't InstanceContextMode.Single working?
我正在尝试在 InstanceContextMode.Single 中将 WCF 服务获取到 运行,这样所有请求都可以共享相同的服务状态。但是,当我尝试以这种行为启动服务时,我仍然可以看到每个请求都会调用服务的构造函数。我想不出更新 ServiceBehaviorAttribute 的快速方法,所以我要替换它(InstanceContextMode 的默认值不是 Single)。似乎在我们启动它时有一个实例,然后是针对稍后出现的所有请求的另一个实例。有什么想法可能会出错吗?
/// <summary>Constructor</summary>
CAutomation::CAutomation()
{
//TODO: pull from config
m_Host = gcnew ServiceHost(CAutomation::typeid, gcnew Uri("http://localhost:8001/GettingStarted"));
// add a service endpoint.
m_Host->AddServiceEndpoint(IAutomation::typeid, gcnew WSHttpBinding(), "Automation");
// add behavior
ServiceMetadataBehavior^ smb = gcnew ServiceMetadataBehavior();
smb->HttpGetEnabled = true;
m_Host->Description->Behaviors->Add(smb);
// enforce single instance behavior
m_Host->Description->Behaviors->RemoveAt(0);
ServiceBehaviorAttribute^ sba = gcnew ServiceBehaviorAttribute();
sba->InstanceContextMode = InstanceContextMode::Single;
m_Host->Description->Behaviors->Add(sba);
}
/// <summary>Starts the automation service.</summary>
void CAutomation::Start()
{
m_Host->Open();
}
通常,您将 ServiceBehaviorAttribute
设置为实现服务的 class 的真实属性。我不是 C++/CLI 专家,但我想既然你将 CAutomation::typeid
传递给 ServiceHost
构造函数,那么 CAutomation
就是你的服务 class。对吗?
如果是这样,那么在 CAutomation
class 上设置 ServiceBehaviorAttribute
就足够了。
Igor Labutin 为我指出了正确的方向,但真正的问题是服务宿主对象的创建将创建一个 class 的实例,其类型被传递给它的构造函数,至少在在 [ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode::Single)]
。基本上,ServiceHost 对象不应该是 CAutomation class 构造函数。我将该对象从该构造函数移到另一个对象中,该对象负责服务何时应该启动并纠正了问题。我将粘贴一段代码示例,这有助于说明更好的方法。
class Program
{
static void Main(string[] args)
{
Uri address = new Uri
("http://localhost:8080/QuickReturns/Exchange");
ServiceHost host = new ServiceHost(typeof(TradeService);
host.Open();
Console.WriteLine("Service started: Press Return to exit");
Console.ReadLine();
}
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,
ReturnUnknownExceptionsAsFaults=true)]
public class TradeService : ITradeService
{
private Hashtable tickers = new Hashtable();
public Quote GetQuote(string ticker)
{
lock (tickers)
{
Quote quote = tickers[ticker] as Quote;
if (quote == null)
{
// Quote doesn't exist
throw new Exception(
string.Format("No quotes found for ticker '{0}'",
ticker));
}
return quote;
}
}
public void PublishQuote(Quote quote)
{
lock (tickers)
{
Quote storedQuote = tickers[quote.Ticker] as Quote;
if (storedQuote == null)
{
tickers.Add(quote.Ticker, quote);
}
else
{
tickers[quote.Ticker] = quote;
}
}
}
}
我正在尝试在 InstanceContextMode.Single 中将 WCF 服务获取到 运行,这样所有请求都可以共享相同的服务状态。但是,当我尝试以这种行为启动服务时,我仍然可以看到每个请求都会调用服务的构造函数。我想不出更新 ServiceBehaviorAttribute 的快速方法,所以我要替换它(InstanceContextMode 的默认值不是 Single)。似乎在我们启动它时有一个实例,然后是针对稍后出现的所有请求的另一个实例。有什么想法可能会出错吗?
/// <summary>Constructor</summary>
CAutomation::CAutomation()
{
//TODO: pull from config
m_Host = gcnew ServiceHost(CAutomation::typeid, gcnew Uri("http://localhost:8001/GettingStarted"));
// add a service endpoint.
m_Host->AddServiceEndpoint(IAutomation::typeid, gcnew WSHttpBinding(), "Automation");
// add behavior
ServiceMetadataBehavior^ smb = gcnew ServiceMetadataBehavior();
smb->HttpGetEnabled = true;
m_Host->Description->Behaviors->Add(smb);
// enforce single instance behavior
m_Host->Description->Behaviors->RemoveAt(0);
ServiceBehaviorAttribute^ sba = gcnew ServiceBehaviorAttribute();
sba->InstanceContextMode = InstanceContextMode::Single;
m_Host->Description->Behaviors->Add(sba);
}
/// <summary>Starts the automation service.</summary>
void CAutomation::Start()
{
m_Host->Open();
}
通常,您将 ServiceBehaviorAttribute
设置为实现服务的 class 的真实属性。我不是 C++/CLI 专家,但我想既然你将 CAutomation::typeid
传递给 ServiceHost
构造函数,那么 CAutomation
就是你的服务 class。对吗?
如果是这样,那么在 CAutomation
class 上设置 ServiceBehaviorAttribute
就足够了。
Igor Labutin 为我指出了正确的方向,但真正的问题是服务宿主对象的创建将创建一个 class 的实例,其类型被传递给它的构造函数,至少在在 [ServiceBehaviorAttribute(InstanceContextMode = InstanceContextMode::Single)]
。基本上,ServiceHost 对象不应该是 CAutomation class 构造函数。我将该对象从该构造函数移到另一个对象中,该对象负责服务何时应该启动并纠正了问题。我将粘贴一段代码示例,这有助于说明更好的方法。
class Program
{
static void Main(string[] args)
{
Uri address = new Uri
("http://localhost:8080/QuickReturns/Exchange");
ServiceHost host = new ServiceHost(typeof(TradeService);
host.Open();
Console.WriteLine("Service started: Press Return to exit");
Console.ReadLine();
}
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,
ReturnUnknownExceptionsAsFaults=true)]
public class TradeService : ITradeService
{
private Hashtable tickers = new Hashtable();
public Quote GetQuote(string ticker)
{
lock (tickers)
{
Quote quote = tickers[ticker] as Quote;
if (quote == null)
{
// Quote doesn't exist
throw new Exception(
string.Format("No quotes found for ticker '{0}'",
ticker));
}
return quote;
}
}
public void PublishQuote(Quote quote)
{
lock (tickers)
{
Quote storedQuote = tickers[quote.Ticker] as Quote;
if (storedQuote == null)
{
tickers.Add(quote.Ticker, quote);
}
else
{
tickers[quote.Ticker] = quote;
}
}
}
}