Introducción
Windows Communication Foundation (WCF) soporta tres modelos de comunicación: solicitado y respuesta, unidireccional y dúplex. En este artículo se analizan los dos primeros, centrándoce en sus características, usos y diferencias clave.
Modelo Solicitado y Respuesta
Este es el comportamiento predeterminado en WCF. El cliente envía una solicitud y permanece bloqueado hasta recibir una respuesta del servidor. Durante ese tiempo, la ejecución se detiene, lo que puede afectar negativamente la exepriencia del usuario si el proceso tarda mucho.
El patrón es ideal para operaciones donde se requiere un resultado explícito, como validaciones o recuperación de datos. Por ejemplo:
[OperationContract]
string ConsultarLibro(string codigo);
Cualquier método marcado con [OperationContract], incluso si devuelve void, sigue siendo parte del modelo solicitado y respuesta. Esto implica que el cliente espera una confirmación de finalización.
Desventajas: Si se realiza una operación costosa (como subir un archivo grande), el cliente queda inactivo durante todo el proceso, lo que reduce su capacidad de respuesta.
Ventajas: Permite devolver información de error detallada al cliente, como mensajes de validación (por ejemplo, "Solo se aceptan archivos .rar").
Modelo Unidireccional
En este modelo, el cliente envía una solicitud y continúa su ejecución sin esperar una respuesta. No hay sincronización ni bloqueo. El servidor recibe el mensaje y lo procesa en segundo plano, lo cual es más eficiente en entornos multithread.
Para habilitar este patrón, se debe configurar la propiedad IsOneWay en [OperationContract]:
[OperationContract(IsOneWay = true)]
void RegistrarEvento(string evento);
Restricciones importantes: Los métodos unidireccionales no pueden tener valores de retorno, parámetros de salida ni referencias. Solo admiten parámetros de entrada.
Este modelo es adecuado para tareas como logs, notificaciones o eventos que no requieren confirmación inmediata.
Ejemplo práctico
Implementación del servicio con ambos patrones:
// Contrato del servicio
[ServiceContract]
public interface ILibroServicio
{
[OperationContract]
string ObtenerLibro(string id);
[OperationContract(IsOneWay = true)]
void EnviarNotificacion(string mensaje);
}
// Implementación del servicio
public class LibroServicio : ILibroServicio
{
public string ObtenerLibro(string id)
{
Thread.Sleep(20000); // Simula un proceso lento
var libro = CrearLibro(int.Parse(id));
return SerializarAxml(libro);
}
public void EnviarNotificacion(string mensaje)
{
Console.WriteLine($"Notificación recibida: {mensaje} a las {DateTime.Now:HH:mm:ss}");
}
}
Cliente que utiliza ambos patrones:
private void btnObtener_Click(object sender, EventArgs e)
{
var cliente = new LibroServicioClient();
textBox1.AppendText($"Inicio: {DateTime.Now:yyyy-MM-dd HH:mm:ss}\r\n");
var resultado = cliente.ObtenerLibro("5");
textBox1.AppendText(resultado + "\r\n");
textBox1.AppendText($"Fin: {DateTime.Now:yyyy-MM-dd HH:mm:ss}\r\n");
}
private void btnEnviar_Click(object sender, EventArgs e)
{
var cliente = new LibroServicioClient();
textBox1.AppendText($"Envío iniciado: {DateTime.Now:yyyy-MM-dd HH:mm:ss}\r\n");
cliente.EnviarNotificacion("Nuevo libro publicado");
textBox1.AppendText($"Continuando sin esperar respuesta... {DateTime.Now:yyyy-MM-dd HH:mm:ss}\r\n");
}
Al ejecutar, el cliente muestra el inicio y fin del llamado de solicitud y respuesta con un retraso significativo, mientras que el método unidireccional se completa casi instantáneamente, demostrando el desacoplamiento entre cliente y servidor.