Compartir a través de


Inyección de dependencias en extensiones de Visual Studio Extensibility

Muchos componentes del SDK de VisualStudio.Extensibility, como controladores de comandos y proveedores de ventanas de herramientas, se implementan como clases individuales. Para ayudar a compartir componentes entre estas clases, el SDK utiliza la inserción de dependencias de .NET para crear instancias de estas clases según sea necesario. Para simplificar el uso compartido de datos entre estos componentes, animamos a los desarrolladores de extensiones a contribuir también a sus componentes compartidos al grafo de inserción de dependencias.

Adición de servicios internos al grafo de inserción de dependencias

Cada extensión del SDK de VisualStudio.Extensibility tiene su propio grafo de servicio que se crea cuando la extensión se carga por primera vez. Las extensiones pueden invalidar el método InitializeServices para agregar sus propios servicios al gráfico de inserción de dependencias. Puede consultar Markdown Linter para obtener un ejemplo de cómo utilizar la inyección de dependencias para compartir un servicio.

Nota

A diferencia del patrón de IServiceProvider del SDK de Visual Studio, estos servicios solo son visibles para otros componentes de la misma extensión y no están pensados para compartirse con otras extensiones.

Servicios proporcionados por el SDK de VisualStudio.Extensibility

Además de los servicios proporcionados por la extensión, el SDK de extensibilidad de VisualStudio.Extensibility agrega los siguientes servicios al grafo al crear la instancia de extensión:

  • TraceSource: se agrega una instancia compartida de TraceSource al gráfico que los componentes pueden usar para registrar advertencias y errores. Estos registros resultan útiles para diagnosticar problemas de informes de clientes con la extensión.

  • VisualStudioExtensibility: instancia de extensibilidad que expone las API para interactuar con Visual Studio, como documentos, editor, área de trabajo.

  • IServiceBroker: Service Broker se puede usar para acceder a servicios intermediados ofrecidos por Visual Studio u otros servicios que es posible que no formen parte del área expuesta de VisualStudioExtensibility.

  • IServiceProvider: el proveedor de servicios se puede usar para consultar servicios dentro del propio grafo de inyección de dependencias de la extensión. Esta instancia no es la misma que el proveedor de servicios global en el proceso de Visual Studio para las extensiones en proceso.

Servicios adicionales para extensiones en proceso

En el caso de las extensiones que se ejecutan en proceso, también están disponibles los siguientes servicios:

  • JoinableTaskFactory y JoinableTaskContext: al ejecutarse como una extensión en proceso mediante otros servicios de Visual Studio, puede ser necesario usar estas instancias para interactuar con el subproceso principal sin provocar interbloqueos. Para obtener más información, consulte Guía paso a paso de subprocesos de Visual Studio.

  • AsyncServiceProviderInjection y MefInjection: estas clases se pueden usar para recuperar servicios en proceso ofrecidos por la infraestructura de IServiceProvider o MEF en los componentes de extensión de VisualStudio.Extensibility. Cuando esté disponible, se recomienda usar primero los servicios ofrecidos por el SDK de extensibilidad de VisualStudio.Extensibility.

  • IAsyncServiceProvider2: esta clase se puede usar como alternativa a AsyncServiceProviderInjection para consultar los servicios de Visual Studio en proceso mediante GetServiceAsync método.

Métodos de extensión proporcionados por el SDK de extensión de Visual Studio Extensibility

Los métodos de extensión de la instancia de IServiceCollection también se pueden usar para ayudar a agregar servicios relacionados con las características de extensibilidad:

  • AddSettingsObservers: este método se genera cuando una extensión contribuye a SettingsCategory y se puede llamar en InitializeServices para insertar servicios de observador para la categoría de configuración proporcionada. Puede hacer referencia a SettingsSample para ver un ejemplo de este método que se está usando.

Duración del servicio

Al agregar un nuevo servicio al gráfico de inserción de dependencias en InitializeServices método, hay tres opciones de duración diferentes. También puede consultar el ejemplo de para ver cómo se utilizan diferentes opciones de vida en una extensión.

  • AddSingleton: estos servicios comparten la misma duración que la instancia de extensión. En la mayoría de los casos, el uso de servicios singleton es la opción adecuada para una extensión del SDK de extensibilidad de VisualStudio.Extensibility.

  • AddTransient: los servicios transitorios crean una nueva instancia de la clase de implementación o llaman al método factory cada vez que un servicio lo consulta. Como resultado, cada componente obtiene su propia instancia del servicio.

  • AddScoped: este ámbito solo se aplica a las clases que tienen el atributo VisualStudioContribution y los servicios consultados por ellos. En el contexto del SDK de extensibilidad de VisualStudio.Extensibility, un ámbito se define mediante la duración de un componente contribuido. En la mayoría de los casos, esta duración es la misma que la duración de la extensión, por lo que los servicios con ámbito y base de datos única se comportarán de la misma manera. La documentación hará una nota especial si hubiera componentes aportados con distintas duraciones.

Caso de uso de ejemplo

En este ejemplo se muestra cómo usar un objeto de origen de datos compartido entre una implementación de ventana de herramientas y un controlador de comandos mediante la inserción de dependencias y InitializeServices.

  • En MyExtension.InitializeServices, MyDataSource se agrega como servicio de base de datos única, ya que se comparte entre los componentes. MyToolWindowControl se agrega como transitorio porque cada instancia de ventana de herramientas debe tener su propia instancia única del control hospedado.

  • En MyToolWindow, insertamos IServiceProvider en el constructor para evitar la inicialización temprana de MyToolWindowControl y, en su lugar, la consulta a través de GetRequiredService cuando sea necesario.

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