共用方式為


Visual Studio Extensibility 擴充功能中的依賴注入

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:Service Broker 可用來存取 Visual Studio 所提供的 代理 服務,或其他不屬於 VisualStudioExtensibility 介面區的服務。

  • IServiceProvider:服務提供者可用來查詢延伸模組本身相依性插入圖形內的服務。 這個實例與 Visual Studio 處理序中的全域服務提供者實例不同,適用於內部處理序中的擴充功能。

處理中延伸模組的其他服務

針對在進程中執行的延伸模組,也可以使用下列服務:

  • JoinableTaskFactoryJoinableTaskContext:當以使用其他 Visual Studio 服務的進程內擴充功能執行時,可能需要利用這些實例來與主線程進行互動,以避免產生死鎖。 如需詳細資訊,請參閱 Visual Studio 線程作手冊

  • AsyncServiceProviderInjectionMefInjection:這些類別可用來擷取 VisualStudio.Extensibility 擴充性元件中 IServiceProviderMEF 基礎結構所提供的進程內服務。 當可用時,建議您先使用 VisualStudio.Extensibility SDK 所提供的服務。

  • IAsyncServiceProvider2:此類別可用作 AsyncServiceProviderInjection 的替代方案,以便利用 GetServiceAsync 方法查詢在進程中的 Visual Studio 服務。

VisualStudio.Extensibility SDK 所提供的擴充方法

IServiceCollection 實例的擴充方法也可用來協助新增與擴充性功能相關的服務:

  • AddSettingsObservers:當延伸模組貢獻 SettingsCategory 時,就會產生這個方法,可以在 InitializeServices 中呼叫,以注入參與的設定類別的觀察者服務。 您可以參考 SettingsSample,以查看正在使用此方法的範例。

服務存留期

InitializeServices 方法中將新的服務新增至相依性插入圖形時,有 3 個不同的存留期選項。 您也可以參考 範例,了解 在擴充功能中如何使用不同的生命週期選項。

  • AddSingleton:這些服務會與擴充實例共用相同的存留期。 在大部分情況下,使用單一服務是 VisualStudio.Extensibility SDK 擴充功能的適當選擇。

  • AddTransient:暫時性服務會建立實作類別的新實例,或每次服務查詢時呼叫 Factory 方法。 因此,每個元件都會取得它自己的服務實例。

  • 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) { }
}