Extensión de distribuidores
Los distribuidores son los responsables de extraer los mensajes entrantes de los canales subyacentes, de modo que los traducen en código de aplicación en las invocaciones de método y devuelven los resultados al autor de la llamada. Las extensiones de distribuidores le permiten modificar este procesamiento. Puede implementar inspectores de parámetro o de mensaje que inspeccionen o modifiquen el contenido de los mensajes o los parámetros. Puede cambiar la manera en la que se enrutan los mensajes a las operaciones o proporcionar otras funcionalidades.
En este tema se describe cómo usar las clases DispatchRuntime y DispatchOperation en una aplicación de servicio de Windows Communication Foundation (WCF) para modificar el comportamiento de ejecución predeterminado de un distribuidor o para interceptar o modificar mensajes, parámetros o valores devueltos antes o después de enviarlos o recuperarlos de la capa de canal. Para más información acerca del procesamiento de mensajes en tiempo de ejecución de cliente equivalente, consulte Extensión de clientes. Para entender la función que desempeñan los tipos IExtensibleObject<T> para acceder al estado compartido entre varios objetos de personalización en tiempo de ejecución, consulte Objetos extensibles.
Distribuidores
El nivel del modelo de servicios realiza la conversión entre el modelo de programación del programador y el intercambio de mensajes subyacentes, comúnmente denominado el nivel de canal. En WCF los distribuidores de canales y puntos de conexión (ChannelDispatcher y EndpointDispatcher, respectivamente) son los componentes de servicio responsables de aceptar nuevos canales, recibir mensajes, distribuir e invocar operaciones y procesar las respuestas. Los objetos de distribuidor son objetos de receptor, pero las implementaciones de contratos de devolución de llamadas en servicios dúplex también exponen sus objetos de distribuidor para la inspección, modificación o extensión.
El distribuidor de canales (y IChannelListener complementario) extrae los mensajes del canal del subordinado y pasa los mensajes a sus distribuidores de extremos respectivos. Cada distribuidor de extremos tiene un DispatchRuntime que enruta los mensajes a la DispatchOperation adecuada, que es responsable de llamar al método que implementa la operación. Durante el proceso, se invocan varias clases de extensiones opcionales y obligatorias. En este tema se explica cómo encajan estas piezas, y cómo podría modificar las propiedades e introducir su propio código para extender la funcionalidad básica.
Las propiedades del distribuidor y los objetos de personalización modificados se insertan utilizando objetos de comportamiento de operación, servicio, punto de conexión, o contrato. En este tema no se describe cómo utilizar los comportamientos. Para más información sobre los tipos usados para insertar modificaciones del distribuidor, consulte Configuración y extensión del tiempo de ejecución con comportamientos.
El siguiente gráfico proporciona una vista de alto nivel de los elementos arquitectónicos de un servicio.
Distribuidores de canal
Se crea un objeto ChannelDispatcher para asociar un IChannelListener de un URI determinado (denominado URI de escucha) a una instancia de un servicio. Cada objeto ServiceHost puede tener muchos objetos ChannelDispatcher, cada uno asociado a un solo agente de escucha y un URI de escucha. Cuando llega un mensaje, el objeto ChannelDispatcher consulta a cada uno de los objetos EndpointDispatcher asociados para saber si el extremo puede aceptar el mensaje, y pasa el mensaje a uno que pueda.
Todas las propiedades que controlan la duración y el comportamiento de una sesión de canal se pueden inspeccionar o modificar en el objeto ChannelDispatcher. Entre ellos se incluyen los inicializadores de canales personalizados, el agente de escuchas de canal, el host, el InstanceContextasociado, etc.
Distribuidores de puntos de conexión
El objeto EndpointDispatcher es responsable de procesar los mensajes de un objeto ChannelDispatcher cuando la dirección de destino de un mensaje coincide con la propiedad AddressFilter y la acción del mensaje coincide con la propiedad ContractFilter. Si dos objetos EndpointDispatcher pueden aceptar un mensaje, el valor de la propiedad FilterPriority determina el punto de conexión de mayor prioridad.
Utilice el EndpointDispatcher para adquirir los dos puntos de extensión de modelo de servicio principales, las clases DispatchRuntime y DispatchOperation, que puede utilizar para personalizar el procesamiento del distribuidor. La clase DispatchRuntime permite a los usuarios interceptar y extender el distribuidor en el ámbito del contrato (es decir, para todos los mensajes de un contrato). La clase DispatchOperation permite a los usuarios interceptar y extender el distribuidor en un ámbito de operación (es decir, para todos los mensajes de una operación).
Escenarios
Hay varias razones para extender el distribuidor:
Validación personalizada del mensaje. Los usuarios pueden exigir que un mensaje sea válido para un determinado esquema. Esto se puede hacer implementando las interfaces del interceptor de mensajes. Para obtener un ejemplo, consulte Inspectores de mensaje.
Registro personalizado de mensajes. Los usuarios pueden inspeccionar y registrar un conjunto de mensajes de la aplicación que fluyen a través de un punto de conexión. Esto también se puede lograr con las interfaces del interceptor de mensajes.
Transformaciones personalizadas del mensaje. Los usuarios pueden aplicar ciertas transformaciones al mensaje en el runtime (por ejemplo, para el control de versiones). Esto también se puede lograr, de nuevo, con las interfaces del interceptor de mensajes.
Modelo de datos personalizado. Los usuarios pueden tener un modelo de serialización de datos distinto de aquellos admitidos de forma predeterminada en WCF (a saber, System.Runtime.Serialization.DataContractSerializer, System.Xml.Serialization.XmlSerializer y los mensajes sin formato). Esto se puede hacer implementando las interfaces del formateador de mensajes. Para obtener un ejemplo, consulte Formateador de operación y selector de operación.
Validación personalizada de parámetros. Los usuarios pueden exigir que los parámetros con tipo sean válidos (por oposición a XML). Esto puede hacerse mediante las interfaces del inspector de parámetros.
Distribución de operaciones personalizadas. Los usuarios pueden implementar la distribución en algo que no sea una acción; por ejemplo, en el elemento de cuerpo o en una propiedad de un mensaje personalizado. Esto se puede hacer mediante la interfaz IDispatchOperationSelector. Para obtener un ejemplo, consulte Formateador de operación y selector de operación.
Agrupación de objetos. Los usuarios pueden agrupar instancias en lugar de asignar una nueva instancia a cada llamada. Esto se puede implementar mediante las interfaces proveedoras de instancias. Para obtener un ejemplo, consulte Agrupación.
Arrendamiento de instancias. Los usuarios pueden implementar un patrón de arrendamiento para la duración de instancias, similar al de .NET Framework Remoting. Esto se puede hacer mediante las interfaces de duración de contexto de instancias.
Control de errores personalizado. Los usuarios pueden controlar cómo se procesan los errores locales y cómo se devuelven los errores a los clientes. Esto se puede implementar utilizando las interfaces IErrorHandler.
Comportamientos de autorización personalizados. Los usuarios pueden implementar un control de acceso personalizado extendiendo las partes en tiempo de ejecución de contratos u operaciones y agregando comprobaciones de seguridad basadas en los tokens presentes en el mensaje. Esto se puede lograr utilizando las interfaces del interceptor de mensajes o del interceptor de parámetros. Para obtener ejemplos, consulte Extensibilidad de la seguridad.
Precaución
Dado que modificar las propiedades de seguridad puede poner en peligro la seguridad de las aplicaciones de WCF, se recomienda encarecidamente que lleve a cabo con mucho cuidado las modificaciones relacionadas con la seguridad y las pruebe antes de realizar la implementación.
Validadores personalizados de WCF en tiempo de ejecución. Puede instalar validadores personalizados que examinen servicios, contratos y enlaces para exigir directivas de empresa con respecto a aplicaciones de WCF. (Para obtener un ejemplo, consulte Cómo bloquear puntos de conexión en la empresa.)
Uso de la clase DispatchRuntime
Utilice la clase DispatchRuntime para modificar el comportamiento predeterminado de punto de conexión individual o de servicio, o para insertar objetos que implementen modificaciones personalizadas en uno o ambos de los siguientes procesos de servicio (o procesos de cliente en el caso de un cliente dúplex):
La transformación de mensajes entrantes en los objetos y la suelta de esos objetos como invocaciones de método en un objeto de servicio.
La transformación de objetos recibidos de la respuesta a una invocación de operación de servicio en mensajes salientes.
DispatchRuntime le permite interceptar y extender el canal o el distribuidor del extremo para todos los mensajes de un contrato determinado, incluso cuando no se reconoce un mensaje. Cuando llega un mensaje que no coincide con ningún mensaje declarado en el contrato, se envía a la operación devuelta por la propiedad UnhandledDispatchOperation. Para interceptar o extenderse por todos los mensajes de una operación determinada, vea la clase DispatchOperation.
Hay cuatro áreas principales de extensibilidad del distribuidor expuestas por la clase DispatchRuntime:
Los componentes de canal utilizan las propiedades de DispatchRuntime y las del distribuidor del canal asociado devueltas por la propiedad ChannelDispatcher para personalizar cómo el distribuidor del canal acepta y cierra los canales. Esta categoría incluye las propiedades ChannelInitializers y InputSessionShutdownHandlers.
Los componentes de mensaje se personalizan para cada mensaje procesado. Esta categoría incluye las propiedades MessageInspectors, OperationSelector, Operations y ErrorHandlers.
Los componentes de instancia personalizan la creación, duración y eliminación de instancias del tipo de servicio. Para obtener más información acerca de la duración de los objetos de servicio, vea la propiedad InstanceContextMode. Esta categoría incluye las propiedades InstanceContextInitializers y InstanceProvider.
Los componentes relacionados con seguridad pueden utilizar las propiedades siguientes:
SecurityAuditLogLocation indica donde se escriben los eventos de auditoría.
ImpersonateCallerForAllOperations controla si el servicio intenta suplantar mediante las credenciales proporcionadas por el mensaje entrante.
MessageAuthenticationAuditLevel controla si los eventos de autenticación de mensajes correctos se escriben en el registro de eventos especificado por SecurityAuditLogLocation.
PrincipalPermissionMode controla cómo se establece la propiedad CurrentPrincipal.
ServiceAuthorizationAuditLevel especifica cómo se realiza la auditoría de eventos de autorización.
SuppressAuditFailure especifica si suprimir excepciones no críticas que producen durante el proceso del registro.
Normalmente, un comportamiento de servicio (un objeto que implementa DispatchRuntime), un comportamiento de contrato (un objeto que implementa IServiceBehavior) o un comportamiento de extremo (un objeto que implementa IContractBehavior) pueden asignar objetos de extensión a una propiedad IEndpointBehavior o insertarlos en una colección. Entonces, el objeto de comportamiento de instalación se agrega a la colección adecuada de comportamientos mediante programación o implementando un objeto BehaviorExtensionElement personalizado para permitir insertar el comportamiento con un archivo de configuración de la aplicación.
Los clientes dúplex (clientes que implementan un contrato de devolución de llamadas especificado por un servicio dúplex) también tienen un objeto DispatchRuntime al que se puede obtener acceso usando la propiedad CallbackDispatchRuntime.
Uso de la clase DispatchOperation
La clase DispatchOperation es la ubicación para las modificaciones en tiempo de ejecución y el punto de inserción para las extensiones personalizadas cuyo ámbito es solo una operación de servicio. (Para modificar el comportamiento del tiempo de ejecución del servicio para todos los mensajes de un contrato, use la clase DispatchRuntime.)
Instale las modificaciones de DispatchOperation utilizando un objeto de comportamiento del servicio personalizado.
Use la propiedad Operations para buscar el objeto DispatchOperation que representa una operación de servicio determinada.
Las siguientes propiedades controlan la ejecución en tiempo de ejecución en el nivel de operación:
Las propiedades Action, ReplyAction, FaultContractInfos, IsOneWay, IsTerminating y Name obtienen los valores correspondientes para la operación.
Las propiedades TransactionAutoComplete y TransactionRequired especifican el comportamiento de transacciones.
Las propiedades ReleaseInstanceBeforeCall y ReleaseInstanceAfterCall controlan la duración del objeto de servicio definido por el usuario relativo a InstanceContext.
Las propiedades DeserializeRequest, SerializeReplyy Formatter habilitan el control explícito sobre la conversión de los mensajes en los objetos, y de los objetos en mensajes.
La propiedad Impersonation especifica el nivel de suplantación de la operación.
La propiedad CallContextInitializers inserta extensiones de contexto de llamada personalizadas para la operación.
La propiedad AutoDisposeParameters controla cuando se destruyen los objetos de parámetro.
La propiedad Invoker se usa para insertar un objeto autor de llamada personalizado.
La propiedad ParameterInspectors permite insertar un inspector de parámetros personalizado que se puede utilizar para inspeccionar o modificar parámetros y valores devueltos.