Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Un servicio mediado es un servicio adquirido a través de un IServiceBroker, y se expone como una interfaz compatible con RPC para permitir que el servicio y su cliente existan en distintos AppDomains, procesos, o incluso entre máquinas (en el caso de Live Share). El servicio intermediado se puede ofrecer desde el proceso principal de Visual Studio o alguno de sus procesos auxiliares, y puede ser consumido por cualquiera de estos procesos mediante una extensión de Visual Studio.
Hay más servicios de Visual Studio (no intermediados) disponibles a través de la IServiceProvider interfaz como se describe en Uso y prestación de servicios. Estos servicios normalmente solo están disponibles en el proceso principal de Visual Studio, pero exponen un mayor conjunto de funcionalidades que los servicios intermediados.
Una extensión de Visual Studio que se ejecuta en un invitado de Live Share puede proporcionar funcionalidad adicional accediendo a un subconjunto de estos servicios como proporcionado por el host de Live Share. Las comprobaciones de autorización se aplican a través de las conexiones de Live Share para mitigar el riesgo de que un invitado de Live Share se comporte mal, lo que pone en peligro la seguridad del host de Live Share. Los autores de servicios asincronados que eligen exponer sus servicios a través de Live Share deben tener cuidado para implementar comprobaciones de autorización, tal como se describe en Cómo proporcionar un servicio asincronizado.
Service Broker
Visual Studio tiene un elemento global IServiceBroker, análogo a (y recuperable desde) el GlobalProvider que expone otro servicio. También es posible recuperarlo a través de MEF.
Puede haber otros brokers de servicio más específicos del contexto que las características especiales de Visual Studio ofrezcan. Estos pueden querer combinar el servicio global con uno propio que ofrezca servicios adicionales (o quizá suprima algunos).
Un IServiceBroker funciona (intencionadamente) como una caja negra que permite a un cliente obtener servicios que pueden ser locales, en otro proceso o en otra máquina. Los intermediarios de servicio pueden ser agregados de uno o de muchos otros, con políticas aplicadas.
En función del contexto en el que se encuentra el proceso de Visual Studio, este agente de servicio global es un agregado de un conjunto cambiante de otros agentes de servicio. Los cambios de contexto dentro del proceso pueden cambiar el conjunto de servicios intermediados que puedan ser activados. Por ejemplo, cuando una solución se carga un servicio específicamente relacionado con la solución activa puede estar disponible. Ese mismo servicio también puede estar disponible en una vista de Carpeta Abierta, aunque con una implementación de respaldo diferente. El cambio en la implementación del servicio sería transparente para un cliente de ese servicio, ya que ambas implementaciones deben cumplir el mismo contrato, pero es necesario que el cliente vuelva a consultar el servicio en este cambio de contexto (del que se les notificará a través AvailabilityChangedde ) para obtener la nueva instancia.
El intermediario de servicios se usa normalmente para obtener un proxy al servicio. Es decir, en lugar de recibir una referencia al objeto de servicio directamente, el cliente recibe un código auxiliar que reenvía todas las llamadas de método al servicio y resultados o excepciones al cliente. También puede reenviar eventos generados por el servicio al cliente. En algunos casos, un servicio puede admitir o requerir que el cliente ofrezca un "objeto de destino" en el que el servicio pueda invocar métodos para volver a llamar al cliente.
Contenedor de servicios intermediados
Los servicios deben ofrecerse en IBrokeredServiceContainer para que estén disponibles desde el IServiceBroker global. Este contenedor de servicios no solo es responsable de exponer la factoría de servicios al agente de servicio, sino también para controlar qué clientes tienen acceso al servicio y notificar a esos clientes cuando cambia el acceso a ese servicio.
Composición de un servicio intermediado
Un servicio intermediado consiste en los siguientes elementos:
- Interfaz que declara la funcionalidad del servicio y actúa como un contrato entre el servicio y sus clientes.
- Implementación de esa interfaz.
- ServiceMoniker para asignar un nombre y una versión al servicio.
- Un ServiceRpcDescriptor que combina el ServiceMoniker con el comportamiento adecuado para controlar RPC cuando sea necesario.
- Código para ofrecer la fábrica de servicios
- Registro de servicios
Interfaz de servicio
Puede ser una interfaz de .NET estándar (a menudo escrita en C#). Para permitir que los clientes y servicios intermediados existan en distintos procesos y se comuniquen a través de RPC, esta interfaz debe cumplir con las restricciones especificadas por el ServiceRpcDescriptor que usará su servicio. Estas restricciones suelen incluir la prohibición de propiedades e indizadores, y que la mayoría o todos los métodos devuelvan Task u otro tipo de valor devuelto compatible con asincronicidad.
Nombres y descriptores de servicios intermediados
La activación de un servicio requiere conocer su moniker. Dado que el apodo se incluye en el descriptor del servicio, un cliente normalmente puede simplemente tratar con el ServiceRpcDescriptor. Un descriptor añade el comportamiento necesario para configurar una conexión RPC entre el servicio intermediado y su cliente, o cuando sea necesario serializar las llamadas RPC hacia/desde un Stream.
Visual Studio recomienda usar el ServiceJsonRpcDescriptor tipo derivado para los servicios intermediados que utilizan la biblioteca StreamJsonRpc cuando el cliente y el servicio requieren RPC para comunicarse. StreamJsonRpc aplica ciertas restricciones en la interfaz de servicio, como se describe aquí .
Un descriptor rara vez debe usarse directamente. En su lugar, normalmente se adquiere desde VisualStudioServices o una biblioteca que ofrece el servicio y, a continuación, se usa como argumento para GetProxyAsync.
Las clases ServiceMoniker y ServiceJsonRpcDescriptor son inmutables y, por tanto, son seguras para compartir como campos o propiedades static readonly.
Cualquier otro ServiceRpcDescriptortipo derivado debe ser inmutable.
Un ServiceMoniker es serializable. Un ServiceJsonRpcDescriptor no es serializable.
Audiencia del servicio
Cada servicio intermediado se registra con una selección de banderas de ServiceAudience. Estas señales controlan a qué clientes y a través de qué conexiones se expondrá el servicio intermediado.
Una selección típica es ServiceAudience.Local, que expone el servicio a cualquier proceso local dentro de una sesión de Visual Studio. Con esta configuración, el servicio siempre se activa localmente, incluso si hay una sesión compartida activa.
Cuando se agrega la ServiceAudience.LiveShareGuest bandera, un invitado de Live Share que solicita ese servicio intermediado obtendrá un proxy a ese servicio intermediado a través de la conexión remota con el host de Live Share.
Cualquier combinación de marcas definidas en ServiceAudience es legal. La LiveShareGuest marca se puede establecer sin establecer también la Local marca, por ejemplo, para exponer un servicio intermediado solo a los invitados de Live Share (desde un host de Live Share) y que nunca esté disponible localmente (donde el cliente y el servicio están en el mismo proceso).
Las banderas RemoteExclusiveClient y RemoteExclusiveServer están en desuso.
Cuando un cliente solicita un servicio intermediado, no necesita saber qué es el ServiceAudience para ese servicio ni dónde se activará el servicio. Sin embargo, puede ser útil para que un servicio documente este valor y para que un desarrollador que consuma el servicio tenga en cuenta dónde se puede activar un servicio para que puedan prever el tipo de datos que pueden provenir de ese servicio en varios contextos y cuándo podría estar disponible un servicio.
Composición de un cliente intermediado
Cuando un cliente solicita un servicio intermediado, se devuelve null cuando el servicio no está disponible, se lanza un ServiceActivationFailedException si falla la activación del servicio, o se obtiene un proxy al servicio.
Se usa un proxy ya sea que el servicio intermediado se active en el mismo proceso que el cliente o en uno diferente.
Este proxy ayuda a armonizar los patrones de uso en los casos de servicio local y remoto para que el cliente no tenga en cuenta dónde se encuentra el servicio.