2012-01-18 22 views
7

en el proceso de creación de un servicio WCF Me encontré con un término que es nuevo para mí. Básicamente cuando especifico el InstanceContextMode tengo algunas opciones, incluyendo; PerSession, PerCall y Single. Aquí está el código de la muestra que estoy aprendiendo de:La vida útil de una instancia de un servicio WCF?

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

Ahora, él indicó que al hacer esto sólo una instancia de mi servicio se crearía en tiempo de ejecución. ¿Qué significa esto? Pensé que cada vez que se establecía una conexión con el servicio web se trataba como una instancia separada.

¿Persiste, esta instancia de mi servicio, para cada solicitud hecha? A juzgar por los otros miembros mencionados en el docs, ¿es seguro asumir que esta es la forma en que funciona?

Respuesta

11

por los documentos:

sólo un objeto InstanceContext se utiliza para todas las llamadas entrantes y es no reciclado posterior a las llamadas. Si no existe un objeto de servicio , se crea uno.

De modo que solo hay una instancia y no se limpia después de realizar una llamada. Esto es como un Singleton para su servicio WCF. Por lo tanto, debe tener cuidado con la memoria compartida y los recursos.

Para responder a su pregunta, sí, así es como funciona.

ACTUALIZACIÓN muestra Agregado: I modificada unas muestras de MSDN para mostrar los efectos de InstanceContextMode.Single. Verá que el conteo de operaciones continuará incrementándose aunque use dos clientes diferentes. Si cambio el InstanceContextMode al PerCall, el recuento será diferente (será cero).

alojado en sí mismo servicio:

[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(); 
    } 
} 

cliente:

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

Entonces, si tuviera una propiedad en mi EvalService del tipo List y le añadí un valor usando un cliente, realmente podría acceder a esa lista desde un cliente diferente (suponiendo que lo haga de esa manera, por supuesto). – loyalpenguin

+0

eso es correcto, siempre es la misma lista . ¡y también cuide el ConcurrencyMode! – blindmeis

+0

lo siento, estaba en una reunión. @blindmeis es correcto. Agregué un ejemplo para demostrar. –

0

Esto significa que sólo una instancia de la clase se crea por la WCF. Todas las solicitudes son manejadas por esa instancia. Se incluyen problemas de subprocesamiento múltiple y concurrencia.

Aunque probablemente sea un detalle de implementación, dudo que su clase sea persistente (debería ser serializable para eso, que no es un requisito). La instancia única existe siempre que sea necesaria (es decir, el ServiceHost asociado está abierto).

0

Sí, compartir la instancia de servicio significa que solo hay una instancia creada por el servidor, compartida entre las solicitudes.

En particular, se llamará una vez al constructor del objeto de servicio cuando se crea la instancia. Esto puede ser importante, por ejemplo, si utiliza alguna forma de autenticación para suplantar la identidad del contexto (las instancias compartidas podrían requerir un poco de trabajo adicional para manejar dicho caso).

4

InstanceContextMode.Single corresponde a un servicio singleton, es decir, el lado del servidor de la instancia de servicio es el mismo para todas las solicitudes entrantes.

Algunos comentarios:

  • de servicio puede ser terminado por el anfitrión, incluso si se trata de un producto único, que es probablemente el caso si su servicio está alojado en IIS
  • Es el contexto instancia que es una Singleton que podría ser disociados de los casos reales de servicio (pero vamos a mantenerlo simple por ahora ...)
  • Si una excepción no se detecta correctamente en un servicio único, que podría impedir cualquier solicitud posterior para tener éxito
+0

¿Por qué IIS termina el servicio? debido al reciclaje de la aplicación o por cualquier otro motivo? – BornToCode

Cuestiones relacionadas