VisualStudio.Extensibility 扩展的组件

使用 VisualStudio.Extensibility 的扩展通常具有多个组件,这些组件也与 Visual Studio 进行交互。

扩展实例

扩展必须具有派生自 Extension的类。 有关示例实现,请参阅 MarkdownLinter

类的 Extension 实例是扩展执行的起点。 此实例包含 Visual Studio 查询扩展提供的服务所需的方法。 它还为扩展提供虚拟方法,以提供本地化资源和扩展拥有的本地服务,以便在扩展的组件之间共享。

该类的配置Extension还包含扩展的元数据,该扩展显示在 Visual Studio 管理扩展窗口中,以及 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"),
    };
    ...

对于熟悉现有 VS SDK API 的 Metadata 扩展开发人员,其中包含 ExtensionConfiguration 的用于生成 .vsixmanifest 文件。 此外,该 Extension 类类似于 AsyncPackage VS SDK 扩展性模型中使用的类。

VisualStudioExtensibility 对象

该对象 VisualStudioExtensibility 充当 Visual Studio 公开的扩展性功能的入口点。 此类具有各种扩展方法、属性,可通过扩展性 SDK 中的可用功能快速枚举。 有关可用方法,请参阅 API 文档。

扩展部件

对于扩展为 Visual Studio 提供组件(如命令、编辑器侦听器)的功能,扩展将使用特性化类。 生成过程将生成正确的元数据,以确保 Visual Studio 能够发现这些组件。

对于扩展为 Visual Studio 提供组件的功能(如命令、编辑器侦听器、工具窗口等),扩展使用带有属性标记的 VisualStudioContribution 类。 生成过程生成正确的元数据,以确保 Visual Studio 能够发现这些组件。

目前,SDK 支持一组有限的组件供稿:

这些类的实例是 SDK 使用依赖项注入库提供的扩展性框架的一部分创建的,构造函数可用于检索 SDK 或扩展本身提供的服务的实例,以便跨组件共享状态。

扩展部件的生存期

每个部件的生存期由在 Visual Studio IDE 进程中加载这些部件的相应组件管理。

  • 当激活相应的命令集时,将初始化命令处理程序,该命令集可以在命令的第一次执行期间初始化。 激活后,命令处理程序应仅在 IDE 关闭时释放。

  • 同样,在 IDE 中加载与指定内容类型匹配的第一个文本视图时,将初始化文本视图事件侦听器。 目前,此类侦听器处于活动状态,直到 IDE 关闭,但此行为将来可能会更改。

通常,对于复杂的扩展,我们建议扩展提供本地服务,部件可以在其构造函数中导入,并使用这些服务跨部件和同一部分的实例共享状态。 这种做法可确保扩展状态不受扩展部件生存期更改的影响。

SDK 提供用于注入的服务

SDK 提供以下服务,可在任何扩展部件的构造函数中使用:

  • VisualStudioExtensibility:每个扩展部件都可以注入一个实例 VisualStudioExtensibility 来与 Visual Studio IDE 交互。

  • Extension:部件可以注入 Microsoft.VisualStudio.Extensibility.Extension 类型或扩展本身从其继承到扩展部件的类型。

  • TraceSource:针对可用于记录诊断信息的每个扩展按需创建跟踪源实例。 这些实例注册到 Visual Studio 诊断 提供程序,该提供程序可用于合并来自多个服务的日志,并利用未来的工具访问实时日志记录。 请参阅 日志记录

  • 本地服务:扩展本身提供的任何本地服务也可用于依赖项注入。

  • MefInjection<TService>AsyncServiceProviderInjection<TService, TInterface>:过程内扩展可以注入传统上通过 MEFAsyncServiceProvider 使用的 Visual Studio SDK 服务。

本地扩展服务

在某些情况下,扩展可能想要在不同的组件(如命令处理程序和文本视图更改侦听器)之间共享状态,如示例中 MarkdownLinter 所示。 可以通过重写 Extension.InitializeServices 方法和创建扩展部件的实例将这些服务添加到进程内服务集合中,这些服务将基于构造函数参数注入。

添加服务有三个选项:

  • AddTransient:将为引入服务的每个部分创建一个新实例。
  • AddScoped:服务的新实例在特定范围内创建。 在 Visual Studio 扩展性上下文中,范围是指单个扩展部件。
  • AddSingleton:在第一次引入时创建单个共享服务实例。

由于对象的生存期 VisualStudioExtensibility 绑定到单个扩展部件的范围,引入对象的任何本地服务都必须是作用域或暂时性服务。 尝试创建注入的单一实例服务 VisualStudioExtensibility 将导致失败。

有关如何使用本地服务的示例,请参阅 MarkdownLinter 扩展

客户端上下文

由于新 SDK 中的所有扩展都用尽了进程,因此我们引入了各种扩展部件的客户端上下文概念,以表示调用事件或方法时 IDE 的状态。 此上下文由 IClientContext SDK 中的实例表示,并传递到各种操作,例如命令执行处理程序。 SDK 提供可用于从上下文中检索对象的扩展方法 IClientContext 。 例如,扩展可以在使用 IClientContext 实例执行命令时获取所选项的活动文本视图或 URI。

某些组件(如命令)还允许声明它们感兴趣的上下文。 这样做是为了优化每个远程执行中传输的数据量,因为客户端上下文将来可能会很大。 在初始预览版中,只有两个可用上下文, ShellEditor在声明命令 CommandAttribute时默认包含这两个上下文。