2012-01-18 55 views
7

在創建WCF服務的過程中遇到了一個對我來說是新的術語。基本上,當指定InstanceContextMode時,我有幾個選項,包括; PerSessionPerCallSingle。下面是從樣品我是從學習對碼:WCF服務的實例的生命週期?

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] 
public class EvalService : IEvalService { ... 

現在,他說通過這樣做,只有一個我的服務的實例在運行時將被創建。這是什麼意思?我認爲每次與Web服務建立連接時都會將其視爲單獨的實例。

對於每一個請求,我的服務的這個實例是否會持續存在?根據docs中提到的其他成員來判斷,假設這是它的工作方式是否安全?

回答

11

每文檔:

僅用於所有來電一個的InstanceContext對象,是 不回收以後的調用。如果服務對象不存在 ,則創建一個。

所以只有一個實例,並且在進行調用後沒有清理。這就像您的WCF服務的單例。所以你需要小心共享內存和資源。

要回答你的問題 - 是的,這是它的工作方式。

UPDATE新增樣本: 我修改了幾個樣品從MSDN展示的InstanceContextMode.Single的影響。即使使用兩個不同的客戶端,您也會看到操作計數將繼續增加。如果我將InstanceContextMode更改爲PerCall,計數將會不同(它將爲零)。

自託管服務:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
public class CalculatorService : ICalculatorInstance 
{ 
    static Object syncObject = new object(); 
    static int instanceCount; 
    int instanceId; 
    int operationCount; 

    public CalculatorService() 
    { 
     lock (syncObject) 
     { 
      instanceCount++; 
      instanceId = instanceCount; 
     } 
    } 

    public double Add(double n1, double n2) 
    { 
     operationCount++; 
     return n1 + n2; 
    } 

    public double Subtract(double n1, double n2) 
    { 
     Interlocked.Increment(ref operationCount); 
     return n1 - n2; 
    } 

    public double Multiply(double n1, double n2) 
    { 
     Interlocked.Increment(ref operationCount); 
     return n1 * n2; 
    } 

    public double Divide(double n1, double n2) 
    { 
     Interlocked.Increment(ref operationCount); 
     return n1/n2; 
    } 

    public string GetInstanceContextMode() 
    { // Return the InstanceContextMode of the service 
     ServiceHost host = (ServiceHost)OperationContext.Current.Host; 
     ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>(); 
     return behavior.InstanceContextMode.ToString(); 
    } 

    public int GetInstanceId() 
    { // Return the id for this instance 
     return instanceId; 
    } 

    public int GetOperationCount() 
    { // Return the number of ICalculator operations performed 
     // on this instance 
     lock (syncObject) 
     { 
      return operationCount; 
     } 
    } 
} 

public class Program 
{ 

    static void Main(string[] args) 
    { 
     Uri baseAddress = new Uri("http://localhost:12345/calc"); 
     using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress)) 
     { 
      // Enable metadata publishing. 
      ServiceMetadataBehavior smb = new ServiceMetadataBehavior(); 
      smb.HttpGetEnabled = true; 
      smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 
      host.Description.Behaviors.Add(smb); 

      // Open the ServiceHost to start listening for messages. Since 
      // no endpoints are explicitly configured, the runtime will create 
      // one endpoint per base address for each service contract implemented 
      // by the service. 
      host.Open(); 

      Console.WriteLine("The service is ready at {0}", baseAddress); 
      Console.WriteLine("Press <Enter> to stop the service."); 
      Console.ReadLine(); 

      // Close the ServiceHost. 
      host.Close(); 
     } 
     Console.WriteLine(); 
     Console.WriteLine("Press <ENTER> to terminate client."); 
     Console.ReadLine(); 
    } 
} 

客戶端:

class Program 
{ 
    static void Main() 
    { 
     // Create a client. 
     CalculatorInstanceClient client = new CalculatorInstanceClient(); 
     string instanceMode = client.GetInstanceContextMode(); 
     Console.WriteLine("InstanceContextMode: {0}", instanceMode); 
     Console.WriteLine("client1's turn"); 
     Console.WriteLine("2 + 2 = {0}", client.Add(2, 2).ToString()); 
     Console.WriteLine("3 - 1 = {0}", client.Subtract(3, 1).ToString()); 
     Console.WriteLine("number of operations = {0}", client.GetOperationCount().ToString()); 

     // Create a second client. 
     CalculatorInstanceClient client2 = new CalculatorInstanceClient(); 

     Console.WriteLine("client2's turn"); 
     Console.WriteLine("2 + 2 = {0}", client2.Add(2, 2).ToString()); 
     Console.WriteLine("3 - 1 = {0}", client2.Subtract(3, 1).ToString()); 
     Console.WriteLine("number of operations = {0}", client2.GetOperationCount().ToString()); 

     Console.WriteLine(); 
     Console.WriteLine("Press <ENTER> to terminate client."); 
     Console.ReadLine(); 
    } 
} 
+0

因此,如果我在我的EvalService類型爲List 中有一個屬性,並且我使用一個客戶端向它添加了一個值,我實際上可以從另一個客戶端訪問該列表(假設我是這樣做的)。 – loyalpenguin

+0

多數民衆贊成在右邊,它總是相同的名單。並照顧併發模式! – blindmeis

+0

對不起 - 我正在開會。 @bindindis是正確的。我添加了一個示例來演示。 –

0

這意味着只有一個你的類的實例被創建WCF。所有請求都由該實例處理。包括多線程和併發問題。

雖然它可能是一個實現細節,但我懷疑你的類是持久化的(它必須是可序列化的,這不是必需的)。一個實例只要需要就存在(即關聯ServiceHost已打開)。

0

是的,共享服務實例意味着只有一個由服務器創建的實例,在請求之間共享。

特別是,當創建實例時,服務對象的構造函數將被調用一次。例如,如果您使用某種形式的身份驗證來模擬上下文的身份(共享實例可能需要一些額外的工作來處理此類情況),這可能很重要。

4

InstanceContextMode.Single對應於單件服務,即對於所有傳入請求,服務實例服務器端是相同的。

幾點意見:

  • 您服務可能通過,即使它是一個單獨的主機被終止,這可能的情況下,如果你的服務託管在IIS
  • 它是一個實例上下文單這可能與實際的服務實例進行分離(但讓我們保持它的簡單,現在...)
  • 如果一個異常沒有在單獨服務正確抓住,它可能會阻止任何後續請求成功
+0

爲什麼IIS終止該服務?由於應用程序回收或任何其他原因? – BornToCode