VisualStudio.Extensibility SDK 的许多组件(如命令处理程序和工具窗口提供程序)作为单个类实现。 为了帮助在这些类之间共享组件,SDK 利用 .NET 依赖项注入 根据需要实例化这些类。 为了简化这些组件之间的数据共享,我们还鼓励扩展开发人员将其共享组件贡献给依赖项注入图。
将内部服务添加到依赖项注入图
VisualStudio.Extensibility SDK 中的每个扩展都有自己的服务图,该图是在首次加载扩展时创建的。 扩展可以替代 InitializeServices 方法,将自己的服务添加到依赖项注入图。 有关使用依赖项注入共享服务的示例,可以参考 Markdown Linter。
注意
与 Visual Studio SDK 的 IServiceProvider
模式不同,这些服务仅对同一扩展中的其他组件可见,并且不会与其他扩展共享。
VisualStudio.Extensibility SDK 提供的服务
除了扩展提供的服务外,VisualStudio.Extensibility SDK 在创建扩展实例时还会向图形添加以下服务:
TraceSource
:将 TraceSource 的共享实例添加到图形中,组件可用于记录警告和错误。 这些日志可用于根据客户报告诊断扩展的问题。VisualStudioExtensibility:公开 API 以与 Visual Studio 交互的扩展性实例,例如文档、编辑器、工作区。
IServiceBroker
:服务代理可用于访问 Visual Studio 提供的 的中转服务,或访问可能不属于VisualStudioExtensibility
外围区域的其他服务。IServiceProvider
:服务提供商可用于在扩展的依赖项注入图中查询服务。 对于进程内扩展,此实例与 Visual Studio 进程中的全局服务提供商不同。
针对进程内扩展的其他服务
对于进程内运行的扩展,还可以使用以下服务:
JoinableTaskFactory
和JoinableTaskContext
:使用其他 Visual Studio 服务作为进程内扩展运行时,可能需要利用这些实例与主线程交互,而不会造成死锁。 有关详细信息,请参阅 Visual Studio 线程处理指南。AsyncServiceProviderInjection 和 MefInjection这些类可用于检索 VisualStudio.Extensibility 扩展组件中由
IServiceProvider
或MEF
基础结构提供的进程内服务。 如果可用,我们建议先使用 VisualStudio.Extensibility SDK 提供的服务。IAsyncServiceProvider2
:此类可替代AsyncServiceProviderInjection
,使用GetServiceAsync
方法查询进程内的 Visual Studio 服务。
VisualStudio.Extensibility SDK 提供的扩展方法
IServiceCollection
实例的扩展方法还可用于帮助添加与扩展性功能相关的服务:
- AddSettingsObservers:当扩展贡献 SettingsCategory 时,将生成此方法,并且可以在
InitializeServices
中调用,从而为所贡献的设置类别注入观察者服务。 可以参考 SettingsSample,查看正在使用此方法的示例。
服务生存期
在 InitializeServices
方法中向依赖项注入图添加新服务时,有 3 个不同的生存期选项。 还可以参考 示例 如何在扩展中使用不同的生存期选项。
AddSingleton
:这些服务共享与扩展实例相同的生存期。 在大多数情况下,使用单一实例服务是 VisualStudio.Extensibility SDK 扩展的适当选择。AddTransient
:暂时性服务创建实现类的新实例,或在每次服务查询时调用工厂方法。 因此,每个组件获取其自己的服务实例。AddScoped
:此范围仅适用于具有VisualStudioContribution
属性的类及其查询的服务。 在 VisualStudio.Extensibility SDK 的上下文中,作用域由参与的组件的生存期定义。 在大多数情况下,此生存期与扩展生存期相同,因此作用域服务与单一实例服务的行为相同。 如果存在具有不同生存期的参与组件,文档将特别说明。
示例用例
此示例演示如何在工具窗口实现与使用依赖项注入和 InitializeServices
的命令处理程序之间使用共享数据源对象。
在
MyExtension.InitializeServices
中,MyDataSource
被添加为单例服务,因为它在组件之间共享。MyToolWindowControl
被添加为瞬态,因为每个工具窗口实例都应具有自己的托管控件的唯一实例。在
MyToolWindow
中,我们在构造函数中注入IServiceProvider
以避免MyToolWindowControl
的早期初始化,并在需要时通过GetRequiredService
对其进行查询。
[VisualStudioContribution]
public class MyExtension : Extension
{
protected override void InitializeServices(IServiceCollection serviceCollection)
{
// Always make sure to call the base method to add required services.
base.InitializeServices(serviceCollection);
serviceCollection.AddSingleton<MyDataSource>();
serviceCollection.AddTransient<MyToolWindowControl>();
}
}
[DataContract]
public class MyDataSource : NotifyPropertyChangedObject
{
}
public class MyToolWindowControl : RemoteUserControl
{
public MyToolWindowControl(MyDataSource dataSource) : base(dataContext)
{
}
}
[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
private readonly IServiceProvider serviceProvider;
public MyToolWindow(IServiceProvider serviceProvider)
{
}
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
var control = this.serviceProvider.GetRequiredService<MyToolWindowControl>();
return Task.FromResult<IRemoteUserControl>(control);
}
}
[VisualStudioContribution]
public class MyCommand : Command
{
public MyCommand(MyDataSource dataSource) { }
}