WCF – Manejo de InstanceContexMode y ConcurrencyContextMode

Wcf Instance and Concurrency mode
Wcf Instance and Concurrency mode

Introducción

En este artículo veremos los 2 tipos de concurrencia más usados y los 3 tipos de creación de instancias disponibles en WCF. Además, veremos las combinaciones disponibles de estos dos atributos, InstanceContextMode y ConcurrencyContextMode, con ejemplos  a través de imágenes para identificar cual es la combinación que podemos usar en un desarrollo según nuestra necesidad.

Manejo de instancia en WCF (InstanceContexMode)

En WCF podemos manejar tres tipo de instancia a nivel de servicio: PerCall, PerSession y Single.

InstanceContexMode.PerCall

Permite crear una instancia del servicio por cada llamada que se realiza.

Servidor
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
public class Servicio : IServicio
{
    private int contador;
    public int IncrementarContador()
    {
        contador++
        return contador;
    }
}

Cliente
ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.IncrementarContador());//Output: 1
Console.WriteLine(proxy.IncrementarContador());//Output: 1
Recomendación

Usar el modo «PerCall» cuando:

  • Se necesita crear un servicio que no almacene estado entre llamadas.
  • El servicio tiene que crear objetos costosos, como conexiones, y necesita liberar recursos lo más rápido posible.
  • Cuando la escalabilidad es un requerimiento y se necesita tener una arquitectura que escale horizontalmente (scale out).
InstanceContexMode.PerSession

Permite crear una instancia del servicio por sesión para mantener el estado entre llamadas.

Servidor
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] 
public class Servicio : IServicio
{
    private int contador;
    public int IncrementarContador()
    {
        contador++
        return contador;
    }
}

Cliente
//Cliente 1
ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.IncrementarContador());//Output: 1
Console.WriteLine(proxy.IncrementarContador());//Output: 2

//Cliente 2
ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.IncrementarContador());//Output: 1
Console.WriteLine(proxy.IncrementarContador());//Output: 2
Recomendación

Usar el modo «PerSession» cuando:

  • Se necesita mantener el estado entre llamadas al servicio.
  • Se necesita tener una arquitectura que escale verticalmente (scale up).
InstanceContexMode.Single

Permite crear solo una instancia del servicio para todas las llamadas.

Servidor
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
public class Servicio : IServicio
{
    private int contador;
    public int IncrementarContador()
    {
        contador++
        return contador;
    }
}

Cliente
//Cliente 1
ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.IncrementarContador());//Output: 1
Console.WriteLine(proxy.IncrementarContador());//Output: 2

//Cliente 2
ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.IncrementarContador());//Output: 3
Console.WriteLine(proxy.IncrementarContador());//Output: 4
Recomendación

Usar el modo «Single» cuando:

  • Se necesita compartir información global en todo el servicio.
  • La escalabilidad no es una necesidad.

Manejo de concurrencia en WCF (ConcurrencyContexMode)

ConcurrencyContextMode.Multiple

Cuando se necesita que múltiples hilos (Thread Request) puedan ser manejados por un servicio WCF. En otras palabras, las solicitudes se procesan al mismo tiempo generando un hilo por cada solicitud. Con esto se logra un gran rendimiento, pero es necesario tener presente los problemas de concurrencia que pueden ocurrir.

ConcurrencyContextMode.Single

Cuando se necesita que solo un hilo (Thread Request) tenga acceso al servicio WCF. Las demás solicitudes tienen que esperar hasta que se complete el proceso de la solicitud anterior.

Configuración de InstanceContexMode y ConcurrencyContextMode

Al usar InstanceContexMode.PerCall y ConcurrencyContextMode.Single ocasiona que se cree un solo Hilo para responder a todas las solicitudes (estas peticiones se encolan) y por cada una se crea una nueva instancia del servicio.

PerCall y Single
PerCall y Single

Al usar InstanceContexMode.PerCall y ConcurrencyContextMode.Multiple ocasiona que se cree un Hilo por cada solicitud y por cada una se crea una nueva instancia del servicio. Esta combinación ofrece mejor rendimiento.

PerCall y Multiple
PerCall y Multiple

Al usar InstanceContexMode.PerSession y ConcurrencyContextMode.Single ocasiona que se cree un solo Hilo para responder a todas las solicitudes (estas peticiones se encolan) y por cada sesión se crea una nueva instancia del servicio.

PerSession y Single
PerSession y Single

Al usar InstanceContexMode.PerSession y ConcurrencyContextMode.Multiple ocasiona que se cree un Hilo por cada solicitud y por cada sesión se crea una nueva instancia del servicio.

PerSession y Multiple
PerSession y Multiple

Al usar el InstanceContexMode.Single y el ConcurrencyContextMode.Single ocasiona que se cree una instancia del servicio y solo un hilo será usado para responder todas las solicitudes.

Single y Single
Single y Single

Al usar el InstanceContexMode.Single y el ConcurrencyContextMode.Multiple ocasiona que se cree una instancia del servicio y que se cree un Hilo por cada solicitud.

Single y Multiple
Single y Multiple

Ajustes en WCF

Cuando existen problemas de rendimiento y concurrencia se debe configurar el servicio WCF para poner un límite al número de llamadas, instancias y sesiones usando la sección Throttling. WCF proporciona tres formas en las que se puede limitar estas características: MaxConcurrentCalls, MaxConcurrentInstances y MaxConcurrentSessions.

  1. MaxConcurrentCalls: Limita el número de solicitudes simultáneas que pueden ser procesados ​​por las instancias de servicio de WCF.
  2. MaxConcurrentInstances: Limita el número de instancias de servicio que se puede asignar en un momento dado. Cuando el servicio está configurado con PerCall, este valor coincide con el número de llamadas simultáneas. Para los servicios de PerSession, este valor es igual al número de instancias de sesiones activas. Este ajuste no tiene importancia para el modo de instancias Single, porque solo una única instancia es creada.
  3. MaxConcurrentSessions: Limita el número de sesiones activas permitidas para el servicio.
<serviceBehaviors> 
<behavior name="serviceBehavior"> 
    <serviceThrottling maxConcurrentCalls="16"
            maxConcurrentInstances="2147483647" 
            maxConcurrentSessions="10" /> 
    </behavior> 
</serviceBehaviors>
Conclusiones:

Se debe usar InstanceContextMode.PerCall si no queremos almacenar estados entre llamadas, InstanceContextMode.PerSession si necesitamos almacenar estados entre llamadas para una sesión  e InstanceContextMode.Single si queremos crear una sola instancia del servicio. Para controlar la concurrencia, las opciones más usadas son: ConcurrencyContextMode.Multiple si queremos que se cree un hilo por cada solicitud y ConcurrencyContextMode.Single si queremos que se cree un solo hilo para atender todas las solicitudes.

Referencias:
Metal Tip:

Este artículo lo escribí escuchando la canción Rain of a thousand flames de la banda Rhapsody of fire de Italia, les comparto el enlace.

Happy coding and Stay Heavy lml

9 comentarios en “WCF – Manejo de InstanceContexMode y ConcurrencyContextMode

      1. Muchas gracias por la información de verdad que nos ayuda a comprender mas estos temas para tener una mejor arquitectura y desde luego mejor rendimiento en nuestras aplicaciones. Saludos

        Me gusta

  1. Muy bueno como siempre lo tuyo , es escencial la vision de diseño y mejores practicas por sobre aprender todo lo nuevo sin dedicarnos a obtener una maestria en lo que tenemos conocimientos.

    Le gusta a 1 persona

  2. Gran artículo, claro y muy explicativo.
    Sólo una duda, he copiado para realizar un ejemplo práctico la opción de InstanceContexMode.PerSession donde la salida debe ser
    //Cliente 1
    ServiceTest proxy = new ServiceTest ();
    Console.WriteLine(proxy.IncrementarContador());//Output: 1
    Console.WriteLine(proxy.IncrementarContador());//Output: 2

    //Cliente 2
    ServiceTest proxy = new ServiceTest ();
    Console.WriteLine(proxy.IncrementarContador());//Output: 1
    Console.WriteLine(proxy.IncrementarContador());//Output: 2

    sin embargo para mí todas las opciones el Output es 1, se comporta como un per call, y la configuración que tengo es:

    En el servidor
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class ServiceTest : IServiceTest
    {
    private int contador;
    public int IncrementarContador()
    {
    contador++;
    return contador;
    }
    }

    y el cliente, exactamente igual que como indicas,

    No sé si podrías saber a que puede ser debido, ya que en mi ejemplo el per call y el per session se comportan igual.

    Gracias.

    Le gusta a 1 persona

    1. Hola Seve, estuve revisando lo que comentas y quisiera saber que tipo de binding usaste?
      Me imagino que fue el basicHttpBinding, ya que es el por defecto, te comento que ese binding no soporta Sesion por la misma naturaleza del protocolo HTTP. En su lugar si quieres usar esta característica debes usar alguno de estos bindings: WsHttpBinding o NetTcpBinding. Te dejo este enlace donde habla más del tema: http://codeidol.com/csharp/wcf/Instance-Management/Per-Session-Services/
      En este otro puedes ver todos los bindings y sus características: https://msdn.microsoft.com/en-us/library/ms730879.aspx

      Saludos

      Me gusta

Deja un comentario