同时使用 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 扩展中,可以参考 这些提示,在同一 VS 扩展项目中托管 VSSDK 扩展和 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 2022 版本 17.9 预览版 1 或更高版本,带有 Visual Studio extension development 工作负载。
  • 如果要从早期版本更新,请确保卸载 VisualStudio.Extensibility Project System 以避免潜在的冲突。

创建扩展项目

  • 使用 VisualStudio.Extensibility Extension with VSSDK Compatibility 模板创建新的解决方案。

VisualStudio.Extensibility 进程内扩展项目模板的屏幕截图。

调试扩展

  • F5 开始调试,这会生成扩展并将其部署到正在使用的 Visual Studio 版本的实验实例。 调试程序应该会在扩展加载后自动附加。

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

    显示示例扩展命令的屏幕截图。

从 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 的服务。

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

    [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 with VSSDK Compatibility 模板用于设置整个项目,但了解与 VS-SDK 兼容的 VisualStudio.Extensibility 扩展插件的基本组件以及它与 “创建第一个扩展”指南中所述的常见变体有何不同,这非常有用。

TargetFramework 和 VssdkCompatibleExtension

扩展项目必须面向目标 Visual Studio 版本使用的 .NET 版本。 对于 Visual Studio 2022,扩展项目必须以 .NET Framework 4.7.2 为目标。

扩展项目还必须包含VssdkCompatibleExtension 属性,且该属性设为 true

<PropertyGroup>
  <VssdkCompatibleExtension>true</VssdkCompatibleExtension>
</PropertyGroup>

RequiresInProcessHosting 属性

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

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

    ...

程序包清单

扩展项目必须包含名为 source.extension.vsixmanifest程序包清单Installation 标记必须将 ExtensionType 设置为 VSSDK+VisualStudio.Extensibility

<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
    <Metadata>
        <Identity Id="MyExtensionId.f14b8c45-154f-4584-abd7-9ec22af003e2" Version="1.0" Language="en-US" Publisher="Microsoft" />
        <DisplayName>My extension</DisplayName>
        <Description xml:space="preserve">My extension's description.</Description>
    </Metadata>
    <Installation ExtensionType="VSSDK+VisualStudio.Extensibility">
        <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.9,18.0)">
            <ProductArchitecture>amd64</ProductArchitecture>
        </InstallationTarget>
      <InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.9,18.0)">
        <ProductArchitecture>arm64</ProductArchitecture>
      </InstallationTarget>
    </Installation>
    <Prerequisites>
        <Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,)" DisplayName="Visual Studio core editor" />
    </Prerequisites>
    <Assets>
        <Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
    </Assets>
</PackageManifest>

从现有 VSSDK 扩展使用 VisualStudio.Extensibility

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

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

  • .csproj 文件中,包括对 VisualStudio.Extensibility API 的包引用:
  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Extensibility" Version="17.9.2092" />
  </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 样式的版本。

  • 删除 Microsoft.VSSDK.BuildTools 的包引用,而是添加 VisualStudio.Extensibility 的包引用。

    <PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.9.2092" />
    <PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.9.2092" />
  • VssdkCompatibleExtension 属性添加到项目文件,将其设置为 true。 此属性将启用一些 VSSDK 功能以实现兼容性。
<PropertyGroup>
    <VssdkCompatibleExtension>true</VssdkCompatibleExtension>
</PropertyGroup>    
  • 创建继承自 Extension 基类的新扩展类,并设置 RequiresInProcessHosting 属性,如前所示。
  • 修改 source.extension.vsixmanifest 文件,将 ExtensionType="VSSDK+VisualStudio.Extensibility" 添加到 Installation 标记。
<Installation ExtensionType="VSSDK+VisualStudio.Extensibility">

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