Partilhar via


Noções básicas de serviço intermediado

Um serviço intermediado é um serviço adquirido por meio de um IServiceBroker, e é exposto como uma interface compatível com RPC para permitir que o serviço e seu cliente existam em AppDomains, processos ou até mesmo entre máquinas distintas (no caso do Live Share). O serviço intermediado pode ser oferecido a partir do processo principal do Visual Studio ou alguns de seus processos auxiliares e pode ser consumido por qualquer um desses processos por uma extensão do Visual Studio.

Mais serviços (não intermediados) do Visual Studio estão disponíveis por meio da interface, IServiceProvider conforme descrito em Usando e fornecendo serviços. Esses serviços normalmente só estão disponíveis no processo principal do Visual Studio, mas expõem um conjunto maior de funcionalidades do que os serviços intermediados.

Uma extensão do Visual Studio em execução em um convidado do Live Share pode fornecer funcionalidade adicional acessando um subconjunto desses serviços, conforme oferecido pelo host do Live Share. As verificações de autorização se aplicam em conexões do Live Share para mitigar o risco de um convidado do Live Share com mau comportamento comprometer a segurança do host do Live Share. Os autores de serviços intermediados que optarem por expor seus serviços pelo Live Share devem ter o cuidado de implementar verificações de autorização conforme descrito em Como fornecer um serviço intermediado.

Intermediário de serviços

O Visual Studio tem um global IServiceBroker, análogo (e recuperável de) o GlobalProvider que expõe outro serviço. Também pode ser recuperado via MEF.

Pode haver outros mediadores de serviços mais específicos de contexto oferecidos por recursos específicos do Visual Studio que pretendem agregar os serviços globais com um dos seus próprios mediadores de serviços que oferece recursos adicionais (ou talvez suprima alguns).

Um IServiceBroker é (intencionalmente) uma caixa preta que permite que um cliente obtenha serviços que podem ser locais, em outro processo ou em outra máquina. Os corretores de serviços podem ser agregados de um ou muitos outros, com políticas aplicadas.

Com base no contexto em que o processo do Visual Studio está, esse agente de serviço global é uma agregação de um conjunto variável de outros agentes de serviço. Alterações de contexto dentro do processo podem alterar o conjunto de serviços intermediados que podem ser ativados. Por exemplo, quando uma solução é carregada, um serviço especificamente relacionado à solução ativa pode ficar disponível. Esse mesmo serviço também pode estar disponível em uma visualização de Pasta Aberta, embora com uma implementação de suporte diferente. A alteração na implementação do serviço seria transparente para um cliente desse serviço, uma vez que ambas as implementações devem cumprir o mesmo contrato, mas o cliente é obrigado a consultar novamente o serviço através dessa alteração de contexto (da qual eles seriam notificados via AvailabilityChanged) para obter a nova instância.

O agente de serviços é normalmente usado para obter um proxy para o serviço. Ou seja, em vez de receber uma referência ao objeto de serviço diretamente, o cliente recebe um stub que encaminha todas as chamadas de método para o serviço e os resultados ou exceções de volta para o cliente. Também pode encaminhar eventos gerados pelo serviço para o cliente. Em alguns casos, um serviço pode oferecer suporte ou exigir que o cliente ofereça um "objeto de destino" no qual o serviço possa invocar métodos para chamar de volta ao cliente.

Contêiner de serviço intermediado

Os serviços devem ser oferecidos no IBrokeredServiceContainer a fim de estar disponível a partir do global IServiceBroker. Esse contêiner de serviço é responsável não apenas por expor a fábrica de serviços ao agente de serviços, mas também por controlar quais clientes têm acesso ao serviço e notificar esses clientes quando o acesso a esse serviço for alterado.

Composição de um serviço intermediado

Um serviço intermediado consiste nos seguintes elementos:

  • Uma interface que declara a funcionalidade do serviço e serve como um contrato entre o serviço e seus clientes.
  • Uma implementação dessa interface.
  • A ServiceMoniker para atribuir um nome e uma versão ao serviço.
  • A ServiceRpcDescriptor que combina o ServiceMoniker com comportamento para lidar com RPC quando necessário.
  • Código para disponibilizar a fábrica de serviços
  • Registo de serviço

Interface de serviço

Esta pode ser uma interface .NET padrão (geralmente escrita em C#). Para permitir que clientes e serviços intermediados existam em processos distintos e se comuniquem por RPC, esta interface deve respeitar as restrições especificadas pelo ServiceRpcDescriptor que o seu serviço utilizará. Essas restrições geralmente incluem que propriedades e indexadores não são permitidos, e a maioria ou todos os métodos retornam Task ou outro tipo de retorno compatível com assíncrono.

Identificadores e descritores de serviço mediado

Ativar um serviço requer conhecer seu nome. Como o apelido está incluído no descritor do serviço, um cliente normalmente pode apenas lidar com o ServiceRpcDescriptor. Um descritor adiciona o comportamento necessário para configurar uma conexão RPC entre o serviço intermediado e seu cliente, ou quando necessário, para serializar chamadas RPC de/para um Stream.

O Visual Studio recomenda o uso do ServiceJsonRpcDescriptor tipo derivado para serviços intermediados que utilizam a biblioteca StreamJsonRpc quando o cliente e o serviço exigem RPC para se comunicar. StreamJsonRpc aplica certas restrições na interface de serviço, conforme descrito aqui .

Um descritor raramente precisa ser usado diretamente. Em vez disso, ele normalmente é adquirido de VisualStudioServices ou uma biblioteca que oferece o serviço e, em seguida, usado como um argumento para GetProxyAsync.

Ambas as ServiceMoniker classes e ServiceJsonRpcDescriptor são imutáveis e, portanto, seguras para compartilhar como static readonly campos ou propriedades. Qualquer outro ServiceRpcDescriptortipo derivado deve ser imutável.

A ServiceMoniker é serializável. A ServiceJsonRpcDescriptor não é serializável.

Público de serviço

Cada serviço intermediado é registado com uma seleção de indicadores de ServiceAudience. Esses sinalizadores controlam quais clientes e sobre quais conexões o serviço intermediado será exposto.

Uma seleção típica é ServiceAudience.Local, que expõe o serviço a qualquer processo local dentro de uma sessão do Visual Studio. Com essa configuração, o serviço é sempre ativado localmente, mesmo que uma sessão Live Shared esteja ativa.

Quando o ServiceAudience.LiveShareGuest sinalizador é adicionado, um convidado do Live Share que solicita esse serviço intermediado receberá um proxy para esse serviço intermediado através da conexão remota com o host do Live Share.

É legal qualquer combinação de bandeiras definidas em ServiceAudience. O LiveShareGuest flag pode ser definido sem também definir o Local flag, por exemplo, para expor um serviço mediado apenas para convidados do Live Share (de um host do Live Share) e nunca disponível localmente (onde cliente e serviço estão no mesmo processo).

As RemoteExclusiveClient bandeiras e RemoteExclusiveServer estão obsoletas.

Quando um cliente solicita um serviço intermediado, ele não precisa saber o ServiceAudience que é para esse serviço ou onde o serviço será ativado. No entanto, pode ser útil para um serviço documentar esse valor e para um desenvolvedor que está consumindo o serviço estar ciente de onde um serviço pode ser ativado, para que possa antecipar o tipo de dados que podem estar vindo desse serviço em vários contextos e quando um serviço pode estar disponível.

Composição de um cliente intermediado

Quando um cliente solicita um serviço intermediado, ele recebe null de volta quando o serviço está indisponível, uma ServiceActivationFailedException exceção se o serviço falhar na ativação, ou recebe um proxy para o serviço. Um proxy é usado se o serviço intermediado é ativado no mesmo processo que o cliente ou em um processo diferente. Esse proxy ajuda a harmonizar os padrões de uso entre os casos de serviço local e remoto para que o cliente não precise saber onde o serviço está localizado.