Componentes de uma extensão VisualStudio.Extensibility
Uma extensão que utiliza o VisualStudio.Extensibility normalmente tem vários componentes que interagem juntos e também com o Visual Studio.
Instância de extensão
As extensões devem ter uma classe derivada de Extension
. Para obter uma implementação de exemplo, consulte MarkdownLinter.
Uma instância da classe Extension
é o ponto de partida para a execução da extensão. Essa instância contém os métodos necessários para o Visual Studio consultar os serviços fornecidos pela extensão. Ele também fornece métodos virtuais para que a extensão forneça recursos localizados e serviços locais de propriedade de extensão a serem compartilhados entre os componentes da extensão.
A configuração da classe Extension
também contém os metadados para a extensão, que é mostrada na janela Gerenciar Extensões do Visual Studio e, para extensões publicadas, no Visual Studio Marketplace .
[VisualStudioContribution]
public class MarkdownLinterExtension : Extension
{
/// <inheritdoc/>
public override ExtensionConfiguration ExtensionConfiguration => new()
{
Metadata = new(
id: "MarkdownLinter.0cf26ba2-edd5-4419-8646-a55d0a83f7d8",
version: this.ExtensionAssemblyVersion,
publisherName: "Microsoft",
displayName: "Markdown Linter Sample Extension",
description: "Sample markdown linter extension"),
};
...
Para desenvolvedores de extensão que estão familiarizados com as APIs existentes do VSSDK, o Metadata
contido em ExtensionConfiguration
é usado para gerar o arquivo .vsixmanifest
. Além disso, a classe Extension
é semelhante à classe AsyncPackage
usada no modelo de extensibilidade do VSSDK.
Objeto VisualStudioExtensibility
O objeto VisualStudioExtensibility
atua como o ponto de entrada para recursos de extensibilidade expostos pelo Visual Studio. Essa classe tem vários métodos de extensão, propriedades para enumerar rapidamente por meio de recursos disponíveis no SDK de extensibilidade. Consulte a documentação da API para obter os métodos disponíveis.
Partes da extensão
Para funcionalidades em que uma extensão adiciona componentes ao Visual Studio, como comandos e escutadores do editor, as extensões utilizarão classes com atributos. O processo de build gerará os metadados corretos para garantir que esses componentes possam ser descobertos pelo Visual Studio.
Para recursos em que uma extensão contribui com componentes para o Visual Studio, como comandos, ouvintes do editor, janelas de ferramentas etc., as extensões utilizam classes marcadas com o atributo VisualStudioContribution
. O processo de build gera os metadados corretos para garantir que esses componentes possam ser descobertos pelo Visual Studio.
Atualmente, o SDK dá suporte a um conjunto limitado de componentes a serem contribuidos:
- manipuladores de comando
- Janelas Ferramenta
- A exibição de texto ativou ouvintes fechados para acompanhar eventos de exibição de texto criados e fechados.
- Ouvintes de alteração de exibição de texto para acompanhar as alterações em uma exibição de texto aberta.
- Provedores de margem
- Visualizadores do depurador
As instâncias dessas classes são criadas como parte da estrutura de extensibilidade fornecida pelo SDK usando uma biblioteca de injeção de dependência e os construtores podem ser usados para recuperar instâncias de serviços fornecidos pelo SDK ou pela própria extensão para compartilhar o estado entre componentes.
Vida útil de peças de extensão
O tempo de vida de cada parte é gerenciado pelo respectivo componente que carrega essas partes dentro do processo do IDE do Visual Studio.
Os manipuladores de comando são inicializados quando o conjunto de comandos correspondente é ativado, o que pode ser durante a primeira execução do comando. Depois de ativados, os manipuladores de comando só devem ser descartados quando o IDE é desligado.
Da mesma forma, os ouvintes de eventos de exibição de texto são inicializados quando a primeira exibição de texto correspondente ao tipo de conteúdo especificado é carregada no IDE. Atualmente, esses ouvintes estão ativos até que o IDE seja desligado, mas esse comportamento pode mudar no futuro.
Em geral, para extensões complexas, recomendamos que as extensões forneçam serviços locais que os componentes possam importar nos respectivos construtores e utilizar esses serviços para compartilhar o estado entre diferentes componentes e instâncias de um mesmo componente. Essa prática garante que o estado da extensão não seja afetado pelas alterações no ciclo de vida das partes de extensão.
Serviços fornecidos pelo SDK para injeção
Os seguintes serviços são fornecidos pelo SDK que pode ser usado no construtor para qualquer parte de extensão:
VisualStudioExtensibility
: cada parte de extensão pode injetar uma instância deVisualStudioExtensibility
para interagir com o IDE do Visual Studio.Extension
: as peças podem injetar o tipoMicrosoft.VisualStudio.Extensibility.Extension
ou o próprio tipo da extensão herdando dele nas peças da extensão.TraceSource
: uma instância de origem de rastreamento é criada sob demanda para cada extensão que pode ser usada para registrar informações de diagnóstico. Essas instâncias são registradas com o provedor de diagnóstico do Visual Studio, que pode ser usado para mesclar logs de vários serviços e utilizar ferramentas futuras para acessar o log em tempo real. Confira Log de eventos.Serviços locais: todos os serviços locais fornecidos pela própria extensão também estarão disponíveis para injeção de dependência.
MefInjection<TService>
eAsyncServiceProviderInjection<TService, TInterface>
: extensões em processo podem injetar os serviços do SDK do Visual Studio que seriam consumidos tradicionalmente por meio do MEF ou do AsyncServiceProvider.
Serviços de extensão comunitária local
Em determinados cenários, uma extensão pode querer compartilhar o estado entre diferentes componentes, como um manipulador de comandos e um ouvinte de alteração de texto, como pode ser visto no exemplo MarkdownLinter
. Esses serviços podem ser adicionados à coleção de serviços em processo, substituindo o método Extension.InitializeServices
. À medida que instâncias de partes de extensão são criadas, os serviços são injetados com base nos argumentos do construtor.
Há três opções para adicionar um serviço:
AddTransient
: uma nova instância do serviço é criada para cada componente que o ingere.AddScoped
: uma nova instância do serviço é criada em um determinado escopo. No contexto de extensibilidade do Visual Studio, o escopo refere-se a uma única parte de extensão.AddSingleton
: há uma única instância de serviço compartilhada criada na primeira ingestão.
Devido ao tempo de vida do objeto VisualStudioExtensibility
estar vinculado ao escopo de uma única parte de extensão, qualquer serviço local que o utiliza deve ser um serviço com escopo ou transitório. A tentativa de criar um serviço singleton que injeta VisualStudioExtensibility
resultará em falha.
Para obter um exemplo de como os serviços locais são usados, consulte a extensão MarkdownLinter .
Contexto do cliente
Como todas as extensões no novo SDK são executadas fora do processo, introduzimos o conceito de contexto do cliente para várias partes de extensão, a fim de representar o estado do IDE no momento em que o evento ou método é invocado. Esse contexto é representado pela instância IClientContext
no SDK e é passado para várias operações, como manipuladores de execução de comando. O SDK fornece métodos de extensão em IClientContext
que podem ser utilizados para recuperar objetos do contexto. Por exemplo, as extensões podem obter o modo de exibição de texto ativo ou o URI para os itens selecionados no momento da execução do comando utilizando a instância IClientContext
.
Alguns componentes, como comandos, também permitem declarar em quais contextos eles estão interessados. Isso é feito para otimizar a quantidade de dados transferidos em cada execução remota, pois o contexto do cliente pode ficar grande no futuro. Na versão prévia inicial, há apenas dois contextos disponíveis, Shell
e Editor
, e ambos são incluídos por padrão ao declarar um comando usando CommandAttribute
.