结合使用 VisualStudio.Extensibility SDK 和 VSSDK

虽然 VisualStudio.Extensibility 模型主要是为了在devenv.exe进程之外托管扩展,但可以在 Visual Studio 进程中运行的扩展中使用 VisualStudio.Extensibility SDK API,并利用 Microsoft.VisualStudio.Sdk 包提供的传统扩展性 API。

支持过程内使用旨在允许早期采用者使用新的 VisualStudio.Extensibility API,同时依赖 Microsoft.VisualStudio.Sdk 来涵盖任何功能差距。

本文档是有关使用 VisualStudio.Extensibility SDK in-proc 的不同选项的快速演练。

  • 如果要开发新的扩展,建议的方法是创建本教程后面的进程内托管的 VisualStudio.Extension。 使用此方法,除了能够注入 VSSDK 和 MEF 服务外,还可以使用 VisualStudio.Extensibility SDK 的完整功能。

  • 如果有现有的 VSSDK 扩展,可以按照 以下提示 在扩展中使用新的 VisualStudioExtensibility 实例。

  • 如果要使用 VisualStudio.Extensibility SDK 将命令、调试可视化工具窗口、工具窗口添加到现有 VSSDK 扩展,可以参考 这些提示 来托管 VSSDK 扩展和同一 VS 扩展项目中的 VisualStudio.Extensibility 扩展。

创建首个与 VSSDK 兼容的 VisualStudio.Extensibility 扩展

虽然 VisualStudio.Extensibility 模型主要是为了在devenv.exe进程之外托管扩展,但从 Visual Studio 2022 17.4 预览版 1 开始,可以生成一个托管在devenv.exe内的 VisualStudio.Extensibility 扩展性扩展插件,并且可以使用 Microsoft.VisualStudio.Sdk 包提供的传统扩展性 API。

先决条件

  • 具有 Visual Studio extension development 工作负载的 Visual Studio 2022 版本 17.9 预览版 1 或更高版本。
  • 如果要从早期版本更新,请确保卸载 VisualStudio.Extensibility Project System 以避免潜在的冲突。

创建扩展项目

  • 使用 VisualStudio.Extensibility Extension with VS SDK Compatibility template 创建新的解决方案。

Screenshot of the VisualStudio.Extensibility in-process extension project template.

调试扩展

  • 容器 项目设置为 启动项目,按 F5 开始调试。

  • 按按 F5 生成扩展并将其部署到正在使用的 Visual Studio 版本的实验实例。 加载扩展后,调试器应附加。

  • 可以在菜单中找到命令 Extensions ,如下图所示:

    Screenshot showing sample extension command.

从 VisualStudio.Extensibility 扩展使用 Visual Studio SDK 服务

与 VS-SDK 兼容的扩展项目引用 Microsoft.VisualStudio.Sdk 包,该包允许访问所有 Visual Studio SDK 的服务。

传统上,此类服务通过 MEFAsyncServiceProvider 使用。 建议使用 VisualStudio.Extensibility 扩展程序注入 .NET 依赖项。

MefInjection<TService>AsyncServiceProviderInjection<TService, TInterface>(来自Microsoft.VisualStudio.Extensibility.VSSdkCompatibility命名空间)允许通过将它们添加到通过依赖项注入实例化的类的构造函数(如命令、工具窗口或扩展部件)来使用 Visual Studio SDK 的服务。

以下示例演示如何 DTE2 将服务和 IBufferTagAggregatorFactoryService 服务添加到命令。

    [VisualStudioContribution]
    public class Command1 : Command
    {
        private TraceSource traceSource;
        private AsyncServiceProviderInjection<DTE, DTE2> dte;
        private MefInjection<IBufferTagAggregatorFactoryService> bufferTagAggregatorFactoryService;

        public Command1(
            VisualStudioExtensibility extensibility,
            TraceSource traceSource,
            AsyncServiceProviderInjection<DTE, DTE2> dte,
            MefInjection<IBufferTagAggregatorFactoryService> bufferTagAggregatorFactoryService)
            : base(extensibility)
        {
            this.dte = dte;
            this.bufferTagAggregatorFactoryService = bufferTagAggregatorFactoryService;
        }
    
        public override CommandConfiguration CommandConfiguration => new("Sample Remote Command")
        {
            Placements = new[] { CommandPlacement.KnownPlacements.ExtensionsMenu },
            Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconAndText),
        };

VSSDK 兼容的 VisualStudio.Extensibility 扩展的剖析

虽然将 VisualStudio.Extensibility Extension 与 VS SDK 兼容性模板配合使用负责设置整个解决方案,但了解 VS-SDK 兼容的 VisualStudio.Extensibility 扩展插件的基本组件与“创建第一个扩展”指南中所述的常见变体有何不同,这非常有用。

容器项目

VS-SDK 兼容的 VisualStudio.Extensibility 解决方案由两个项目组成:

  1. 引用 VisualStudio.Extensibility 和 Visual Studio SDK 包并包含扩展的所有代码的类库,
  2. 用于部署和调试扩展的容器 VSIX 项目。

此分离是临时解决方案,而 VisualStudio.Extensibility 处于预览状态,最终打包和部署设计正在完成。

扩展程序不应将代码、内容或资源添加到容器项目。 容器项目的唯一目标是包括其他项目提供的资产。

TargetFramework

扩展项目和容器项目都必须面向目标 Visual Studio 版本使用的 .NET 版本。 对于 Visual Studio 2022,它们必须面向 .NET Framework 4.7.2。

RequiresInProcessHosting 属性

Extension必须使用将扩展标识为进程内的属性来配置RequiresInProcessHosting = true该类。

[VisualStudioContribution]
internal class MyExtension : Extension
{
    public override ExtensionConfiguration? ExtensionConfiguration => new()
    {
        RequiresInProcessHosting = true,
    };

    ...

使用现有 VSSDK 扩展中的 VisualStudio.Extensibility

对于现有的 VSSDK 扩展,另一个选项是通过服务提供商查询 VisualStudioExtensibility 实例并利用其方法。 此方法允许在现有组件中使用 VisualStudio.Extensibility SDK 的新 API 外围应用。 在想要使用新 API 查询项目信息、文档管理而不创建新的基于 VisualStudio.Extensibility 的扩展的情况下,此选项非常有用。

下面是一个示例代码片段,演示如何在 VisualStudioExtensibility VSSDK 包中使用:

  • .csproj在文件中,包括对 VisualStudio.Extensibility API 的包引用:
  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Extensibility" Version="17.9.23-preview-1" />
  </ItemGroup>
...
using Microsoft.VisualStudio.Extensibility;
...

public class VSSDKPackage : AsyncPackage
{
    protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
    {
        VisualStudioExtensibility extensibility = await this.GetServiceAsync<VisualStudioExtensibility, VisualStudioExtensibility>();
        await extensibility.Shell().ShowPromptAsync("Hello from in-proc", PromptOptions.OK, cancellationToken);
        ...
    }
}

向现有 VSSDK 扩展项目添加 VisualStudio.Extensibility 扩展

如果还想要在现有 VSSDK 扩展内使用 VisualStudio.Extensibility SDK 的编辑器侦听器(如工具窗口)提供组件,则必须按照其他步骤在项目中创建 VisualStudio.Extensibility Extension 实例。

  • 需要使用 SDK 样式 .csproj 才能使用 VisualStudio.Extensibility SDK 包。 对于现有项目,可能需要将自己的 .csproj SDK 样式更新为 SDK 样式。

  • 删除 VisualStudio.Extensibility 的 Microsoft.VSSDK.BuildTools 包引用,并改为添加包引用。

    <PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.9.23-preview-1" />
    <PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.9.23-preview-1" />
  • 将属性添加到 VssdkCompatibleExtension 项目文件,将其设置为 true. 此属性将启用一些 VSSDK 功能以实现兼容性。
<PropertyGroup>
    <VssdkCompatibleExtension>true</VssdkCompatibleExtension>
</PropertyGroup>    

现在,可以将 VisualStudio.Extensibility 的所有功能与现有的 VSSDK 扩展一起使用。