Partilhar via


Componentes de uma extensão VisualStudio.Extensibility

Uma extensão que utiliza 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 um exemplo de implementação, 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 que o Visual Studio consulte 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 da extensão a serem compartilhados entre os componentes da extensão.

A configuração da classe Extension também contém os metadados da extensão que são mostrados 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 VSSDK existentes, 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 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.

Peças de extensão

Para recursos em que uma extensão contribui com componentes para o Visual Studio, como comandos, ouvintes do editor, as extensões utilizarão classes atribuídas. O processo de compilação 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 compilação gera os metadados corretos para garantir que esses componentes possam ser descobertos pelo Visual Studio.

Atualmente, o SDK oferece suporte a um conjunto limitado de componentes a serem contribuídos:

As instâncias para essas 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 os componentes.

Vida útil das 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 comandos são inicializados quando o conjunto de comandos correspondente é ativado, o que pode ocorrer durante a primeira execução do comando. Uma vez ativados, os manipuladores de comandos só devem ser descartados quando o IDE for 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 as partes possam importar em seu construtor e usar esses serviços para compartilhar o estado entre partes e entre instâncias da mesma peça. Essa prática garante que o estado da extensão não seja afetado por alterações de tempo de vida das peças de extensão.

Serviços fornecidos pelo SDK para injeção

Os seguintes serviços são fornecidos pelo SDK que podem ser usados no construtor para qualquer parte de extensão:

  • VisualStudioExtensibility: cada parte da extensão pode injetar uma instância de VisualStudioExtensibility para interagir com o IDE do Visual Studio.

  • Extension: as peças podem injetar o tipo Microsoft.VisualStudio.Extensibility.Extension ou o próprio tipo de extensões herdadas dele para as peças de 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. Consulte Registro em log.

  • 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> e AsyncServiceProviderInjection<TService, TInterface>: as extensões In-proc podem injetar serviços SDK do Visual Studio que seriam tradicionalmente consumidos por meio do MEF ou do AsyncServiceProvider.

Serviços de extensão 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 exibiçã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 e, à 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 parte que o ingere.
  • AddScoped: uma nova instância do serviço é criada dentro de um determinado escopo. No contexto da extensibilidade do Visual Studio, o escopo refere-se a uma única parte da extensão.
  • AddSingleton: há uma única instância compartilhada de serviço que é criada na primeira ingestão.

Devido ao tempo de vida do objeto VisualStudioExtensibility estar associado ao escopo de uma única parte de extensão, qualquer serviço local que o ingere deve ser um serviço com escopo ou transitório. Tentar 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 Extensão MarkdownLinter.

Contexto do cliente

Como todas as extensões no novo SDK ficam fora do processo, introduzimos o conceito de contexto do cliente para várias partes de extensão para representar o estado do IDE no momento em que o evento ou método é chamado. 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 a exibição de texto ativa 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 que você declare 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 visualização 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.