Informazioni di base sul servizio negoziato
Un servizio negoziato è un servizio acquisito tramite IServiceBrokere viene esposto come interfaccia compatibile con RPC per consentire al servizio e al relativo client di esistere in appDomain distinti, processi o anche tra computer (nel caso di Live Share). Il servizio negoziato può essere profferato dal processo principale di Visual Studio o da alcuni dei processi ausiliari e può essere utilizzato da uno di questi processi da un'estensione di Visual Studio.
Altri servizi di Visual Studio non negoziati sono disponibili tramite l'interfaccia IServiceProvider come descritto in Uso e fornitura di servizi. Tali servizi sono in genere disponibili solo nel processo principale di Visual Studio, ma espongono un set di funzionalità più ampio rispetto ai servizi negoziati.
Un'estensione di Visual Studio in esecuzione in un guest di Live Share può offrire funzionalità aggiuntive accedendo a un subset di questi servizi come offerto dall'host di Live Share. I controlli di autorizzazione si applicano sulle connessioni di Live Share per ridurre il rischio di un guest di Live Share che non funziona correttamente compromettendo la sicurezza dell'host di Live Share. Gli autori di servizi negoziati che scelgono di esporre i propri servizi tramite Live Share devono occuparsi dell'implementazione dei controlli di autorizzazione, come descritto in Come fornire un servizio negoziato.
Service Broker
Visual Studio ha un oggetto globale IServiceBrokeranalogo a (e recuperabile da) GlobalProvider che espone altri servizi. Può anche essere recuperato tramite MEF.
Potrebbero esserci altri broker di servizi specifici del contesto disponibili in base a funzionalità specifiche di Visual Studio che vogliono aggregare quello globale con uno dei propri servizi che offrono servizi aggiuntivi (o ad esempio elimina alcuni).
Un IServiceBroker è (intenzionalmente) una scatola nera che consente a un client di ottenere servizi che possono essere locali, in un altro processo o in un altro computer. I broker di servizio possono essere aggregati di uno o più altri, con criteri applicati.
In base al contesto in cui si trova il processo di Visual Studio, questo service broker globale è un'aggregazione di un set di modifica di altri broker di servizi. Le modifiche di contesto all'interno del processo possono modificare il set di servizi negoziati che possono essere attivati. Ad esempio, quando una soluzione viene caricata, un servizio correlato specificamente alla soluzione attiva può diventare disponibile. Lo stesso servizio può essere disponibile anche in una visualizzazione Apri cartella, anche se con un'implementazione di backup diversa. La modifica nell'implementazione del servizio sarebbe trasparente per un client di tale servizio poiché entrambe le implementazioni devono soddisfare lo stesso contratto, ma il client deve eseguire nuovamente una query per il servizio in questa modifica del contesto (di cui verrebbero informati tramite AvailabilityChanged) per ottenere la nuova istanza.
Service Broker viene in genere usato per ottenere un proxy al servizio. In questo caso, anziché ricevere direttamente un riferimento all'oggetto servizio, il client riceve uno stub che inoltra tutte le chiamate al metodo al servizio e restituisce risultati o eccezioni al client. Può anche inoltrare gli eventi generati dal servizio al client. In alcuni casi un servizio può supportare o richiedere che il client offra un "oggetto di destinazione" su cui il servizio può richiamare i metodi per richiamare il client.
Contenitore di servizi negoziati
I servizi devono essere inseriti nell'oggetto IBrokeredServiceContainer per poter essere disponibili dall'oggetto globale IServiceBroker. Questo contenitore di servizi è responsabile non solo dell'esposizione della factory del servizio al service broker, ma anche del controllo dei client che hanno accesso al servizio e di notificare a tali client quando l'accesso a tale servizio cambia.
Composizione di un servizio negoziato
Un servizio negoziato è costituito dagli elementi seguenti:
- Interfaccia che dichiara la funzionalità del servizio e funge da contratto tra il servizio e i relativi client.
- Implementazione di tale interfaccia.
- Oggetto ServiceMoniker per assegnare un nome e una versione al servizio.
- Oggetto ServiceRpcDescriptor che combina l'oggetto con il ServiceMoniker comportamento per la gestione di RPC quando necessario.
- Codice per il proffering della factory del servizio
- Registrazione del servizio
Interfaccia del servizio
Può trattarsi di un'interfaccia .NET standard (spesso scritta in C#). Per consentire l'esistenza di servizi e client di servizi negoziati in processi distinti e comunicare tramite RPC, questa interfaccia deve rispettare le restrizioni specificate dall'oggetto ServiceRpcDescriptor che verrà usato dal servizio. Queste restrizioni includono in genere che le proprietà e gli indicizzatori non sono consentiti e la maggior parte o tutti i metodi restituiscono Task o un altro tipo restituito compatibile con asincrona.
Moniker e descrittori del servizio negoziati
L'attivazione di un servizio richiede la conoscenza del relativo moniker. Poiché il moniker è incluso nel descrittore del servizio, un client in genere può gestire solo l'oggetto ServiceRpcDescriptor. Un descrittore aggiunge il comportamento necessario per configurare una connessione RPC tra il servizio negoziato e il client o quando necessario per serializzare le chiamate RPC a/da un oggetto Stream.
Visual Studio consiglia di usare il ServiceJsonRpcDescriptor tipo derivato per i servizi negoziati che utilizza la libreria StreamJsonRpc quando il client e il servizio richiedono RPC per comunicare. StreamJsonRpc applica alcune restrizioni all'interfaccia del servizio, come descritto qui.
Un descrittore raramente deve essere usato direttamente. Invece, viene in genere acquisito da VisualStudioServices o da una libreria che offre il servizio, quindi usato come argomento per GetProxyAsync.
Entrambe le ServiceMoniker classi e ServiceJsonRpcDescriptor sono non modificabili e pertanto sono sicure da condividere come static readonly
campi o proprietà.
Qualsiasi altro ServiceRpcDescriptortipo derivato da deve essere non modificabile.
Un ServiceMoniker oggetto è serializzabile. Un ServiceJsonRpcDescriptor oggetto non è serializzabile.
Destinatari del servizio
Ogni servizio negoziato viene registrato con una selezione di flag da ServiceAudience. Questi flag controllano i client e le connessioni a cui verrà esposto il servizio negoziato.
Una selezione tipica è ServiceAudience.Local, che espone il servizio a qualsiasi processo locale all'interno di una sessione di Visual Studio. Con questa impostazione, il servizio viene sempre attivato in locale, anche se è attiva una sessione condivisa dinamica.
Quando viene aggiunto il ServiceAudience.LiveShareGuest flag, un guest di Live Share che richiede che il servizio negoziato ottenga un proxy al servizio negoziato tramite la connessione remota con l'host di Live Share.
Qualsiasi combinazione di flag definiti in ServiceAudience è legale. Il LiveShareGuest flag può essere impostato senza impostare anche il Local flag, ad esempio per esporre un servizio negoziato solo agli utenti guest di Live Share (da un host di Live Share) e non essere mai disponibili in locale (dove client e servizio si trovano nello stesso processo).
I RemoteExclusiveClient flag e RemoteExclusiveServer sono deprecati.
Quando un client richiede un servizio negoziato, non è necessario sapere qual ServiceAudience è per tale servizio o dove verrà attivato il servizio. Tuttavia, può essere utile per un servizio documentare questo valore e per uno sviluppatore che utilizza il servizio per essere a conoscenza della posizione in cui un servizio potrebbe essere attivato in modo da prevedere il tipo di dati che potrebbero provenire da tale servizio in vari contesti e quando un servizio potrebbe essere disponibile.
Composizione di un client negoziato
Quando un client richiede un servizio negoziato, viene null
restituito quando il servizio non è disponibile, ServiceActivationFailedException viene generato se il servizio non riesce nell'attivazione o ottiene un proxy al servizio.
Viene usato un proxy che indica se il servizio negoziato viene attivato nello stesso processo del client o in uno diverso.
Questo proxy consente di uniformare i modelli di utilizzo nei casi di servizio locali e remoti in modo che il client non debba essere a conoscenza della posizione del servizio.