Comment : fournir un Service asynchrone Visual StudioHow to: Provide an Asynchronous Visual Studio Service

Si vous souhaitez obtenir un service sans bloquer le thread d’interface utilisateur, vous créez un service asynchrone et charger le package sur un thread d’arrière-plan.If you want to obtain a service without blocking the UI thread, you should create an asynchronous service and load the package on a background thread. Pour cela, vous pouvez utiliser un AsyncPackage plutôt qu’un Package, ajoutez le service avec des méthodes asynchrones du package asynchrone spéciales.For this purpose you can use an AsyncPackage rather than a Package, and add the service with the asynchronous package's special asynchronous methods.

Pour plus d’informations sur la fourniture des services Visual Studio synchrones, consultez Comment : fournir un Service.For information about providing synchronous Visual Studio services, see How to: Provide a Service.

Implémentation d’un Service asynchroneImplementing an Asynchronous Service

  1. Créez un projet VSIX (fichier > Nouveau > projet > c# > Extensiblity > projet VSIX).Create a VSIX project (File > New > Project > Visual C# > Extensiblity > VSIX Project). Nommez le projet TestAsync.Name the project TestAsync.

  2. Ajouter un VSPackage au projet.Add a VSPackage to the project. Sélectionnez le nœud de projet dans le l’Explorateur de solutions et cliquez sur Ajouter > nouvel élément > éléments Visual c# > extensibilité > Package Visual Studio.Select the project node in the Solution Explorer and click Add > New item > Visual C# Items > Extensibility > Visual Studio Package. Nommez ce fichier TestAsyncPackage.cs.Name this file TestAsyncPackage.cs.

  3. Dans TestAsyncPackage.cs, modifiez le package d’hériter de AsyncPackage au lieu de Package :In TestAsyncPackage.cs, change the package to inherit from AsyncPackage rather than Package:

    public sealed class TestAsyncPackage : AsyncPackage  
    
  4. Pour implémenter un service, vous devez créer trois types :To implement a service, you need to create three types:

    • Interface qui identifie le service.An interface that identifies the service. La plupart de ces interfaces sont vides, autrement dit, ils n’ont aucune méthode qu’elles sont uniquement utilisées pour interroger le service.Many of these interfaces are empty, that is, they have no methods as they are only used for querying the service.

    • Interface qui décrit l’interface de service.An interface that describes the service interface. Cette interface comprend les méthodes à implémenter.This interface includes the methods to be implemented.

    • Une classe qui implémente le service et l’interface de service.A class that implements both the service and the service interface.

  5. L’exemple suivant montre une implémentation de base des trois types.The following example shows a very basic implementation of the three types. Le constructeur de la classe de service doit définir le fournisseur de services.The constructor of the service class must set the service provider. Dans cet exemple, nous allons simplement ajouter le service dans le fichier de code du package.In this example we'll just add the service to the package code file.

  6. Ajoutez le code suivant à l’aide des instructions pour le fichier de package :Add the following using statements to the package file:

    using System.Threading;  
    using System.Threading.Tasks;  
    using System.Runtime.CompilerServices;  
    using System.IO;
    using Microsoft.VisualStudio.Threading;
    using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider;
    using Task = System.Threading.Tasks.Task;
    
  7. Voici l’implémentation de service asynchrone.Here's the asynchronous service implementation. Notez que vous devez définir le fournisseur de service asynchrone plutôt que le fournisseur de service synchrones dans le constructeur :Note that you need to set the asynchronous service provider rather than the synchronous service provider in the constructor:

    public class TextWriterService : STextWriterService, ITextWriterService  
    {  
        private IAsyncServiceProvider asyncServiceProvider;  
    
        public TextWriterService(IAsyncServiceProvider provider)  
        {
            // constructor should only be used for simple initialization
            // any usage of Visual Studio service, expensive background operations should happen in the
            // asynchronous InitializeAsync method for best performance
            asyncServiceProvider = provider;  
        }
    
        public async Task InitializeAsync(CancellationToken cancellationToken)
        {
            await TaskScheduler.Default;
            // do background operations that involve IO or other async methods
    
            await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);               
            // query Visual Studio services on main thread unless they are documented as free threaded explicitly.
            // The reason for this is the final cast to service interface (such as IVsShell) may involve COM operations to add/release references.
    
            IVsShell vsShell = this.asyncServiceProvider.GetServiceAsync(typeof(SVsShell)) as IVsShell;
            // use Visual Studio services to continue initialization
        }
    
        public async Task WriteLineAsync(string path, string line)  
        {  
            StreamWriter writer = new StreamWriter(path);  
            await writer.WriteLineAsync(line);  
            writer.Close();  
        }  
    }  
    
    public interface STextWriterService  
    {  
    }  
    
    public interface ITextWriterService   
    {  
        System.Threading.Tasks.Task WriteLineAsync(string path, string line);  
    }  
    

L’inscription d’un ServiceRegistering a Service

Pour inscrire un service, ajoutez le ProvideServiceAttribute au package qui fournit le service.To register a service, add the ProvideServiceAttribute to the package that provides the service. Différent de l’inscription d’un service synchrone, vous devez vous assurer package et le service prend en charge asynchrone du chargement :Different to registering a synchronous service, you have to make sure both package and service supports async loading:

  • Vous devez ajouter le AllowsBackgroundLoading = true au champ la PackageRegistrationAttribute pour vérifier le package peut être initialisé de façon asynchrone pour plus d’informations sur la PackageRegistrationAttribute, voir inscription et Annulation de l’inscription de VSPackages.You must add the AllowsBackgroundLoading = true field to the PackageRegistrationAttribute to ensure package can be initialized asynchronously For more information about the PackageRegistrationAttribute, see Registering and Unregistering VSPackages.

  • Vous devez ajouter le IsAsyncQueryable = true au champ la ProvideServiceAttribute pour vous assurer de l’instance de service peut être initialisé de façon asynchrone.You must add the IsAsyncQueryable = true field to the ProvideServiceAttribute to ensure service instance can be initialized asynchronously.

    Voici un exemple d’un AsyncPackage avec une inscription de service asynchrone :Here is an example of an AsyncPackage with an asynchronous service registration:

[ProvideService((typeof(STextWriterService)), IsAsyncQueryable = true)]  
[ProvideAutoLoad(UIContextGuids80.SolutionExists, PackageAutoLoadFlags.BackgroundLoad)]  
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]   
[Guid(TestAsyncPackage.PackageGuidString)]  
public sealed class TestAsyncPackage : AsyncPackage  
{. . . }  

Ajout d’un serviceAdding a service

  1. Dans TestAsyncPackage.cs, supprimez le Initialize() (méthode) et que vous remplacez le InitializeAsync() (méthode).In TestAsyncPackage.cs, remove the Initialize() method and override the InitializeAsync() method. Ajoutez le service et ajoutez une méthode de rappel pour créer les services.Add the service, and add a callback method to create the services. Voici un exemple de l’initialiseur asynchrone Ajout d’un service :Here is an example of the asynchronous initializer adding a service:

    protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)  
    {  
        await base.InitializeAsync(cancellationToken, progress);  
        this.AddService(typeof(STextWriterService), CreateTextWriterService);
    }  
    
  2. Ajoutez une référence à Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll.Add a reference to Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll.

  3. Implémentez la méthode de rappel comme une méthode asynchrone qui crée et retourne le service.Implement the callback method as an asynchronous method that creates and returns the service.

    public async Task<object> CreateTextWriterService(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType)  
    {  
        TextWriterService service = new TextWriterService(this);  
        await service.InitializeAsync(cancellationToken);
        return service;
    }  
    

À l’aide d’un ServiceUsing a Service

Vous pouvez désormais obtenir le service et utiliser ses méthodes.Now you can get the service and use its methods.

  1. Nous allons montrer ce dans l’initialiseur, mais vous pouvez obtenir le service n’importe où que vous souhaitez utiliser le service.We'll show this in the initializer, but you can get the service anywhere you want to use the service.

    protected override async System.Threading.Tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)  
    {  
        await base.InitializeAsync(cancellationToken, progress);  
        this.AddService(typeof(STextWriterService), CreateTextWriterService);  
    
        ITextWriterService textService = await this.GetServiceAsync(typeof(STextWriterService)) as ITextWriterService;  
    
        await textService.WriteLineAsync(<userpath>), "this is a test");  
    }  
    

    N’oubliez pas de modifier <userpath > à un nom de fichier et le chemin d’accès logique sur votre ordinateur.Don't forget to change <userpath> to a filename and path that makes sense on your machine!

  2. Générez et exécutez le code.Build and run the code. Lorsque l’instance expérimentale de Visual Studio s’affiche, ouvrez une solution.When the experimental instance of Visual Studio appears, open a solution. Cela entraîne le AsyncPackage à autoload.This causes the AsyncPackage to autoload. Lors de l’initialiseur a été exécuté, vous devez rechercher un fichier dans l’emplacement spécifié.When the initializer has run, you should find a file in the location you specified.

À l’aide d’un Service asynchrone dans un gestionnaire de commandesUsing an Asynchronous Service in a Command Handler

Voici un exemple montrant comment utiliser un service asynchrone dans une commande de menu.Here's an example of how to use an asynchronous service in a menu command. Vous pouvez utiliser la procédure ci-après pour utiliser le service dans d’autres méthodes non asynchrone.You can use the procedure shown here to use the service in other non-asynchronous methods.

  1. Ajouter une commande de menu à votre projet.Add a menu command to your project. (Dans le l’Explorateur de solutions, sélectionnez le nœud de projet, avec le bouton droit, puis sélectionnez Ajouter / nouvel élément / extensibilité personnalisée commande.) Nommez le fichier de commandes TestAsyncCommand.cs.(In the Solution Explorer, select the project node, right-click, and select Add / New Item / Extensibility / Custom Command.) Name the command file TestAsyncCommand.cs.

  2. Le modèle de commande personnalisée ajoute de nouveau la Initialize() méthode dans le fichier TestAsyncPackage.cs afin d’initialiser la commande.The custom command template re-adds the Initialize() method to the TestAsyncPackage.cs file in order to initialize the command. Dans la méthode Initialize(), copiez la ligne qui initialise la commande.In the Initialize() method, copy the line that initializes the command. Le résultat doit être semblable à ce qui suit :It should look like this:

    TestAsyncCommand.Initialize(this);  
    

    Déplacer cette ligne de la InitializeAsync() méthode dans le fichier AsyncPackageForService.cs.Move this line to the InitializeAsync() method in the AsyncPackageForService.cs file. Dans la mesure où il s’agit de l’initialisation asynchrone, vous devez basculer vers le thread principal avant d’initialiser l’à l’aide de la commande SwitchToMainThreadAsync.Since this is in an asynchronous initialization, you must switch to the main thread before you initialize the command using SwitchToMainThreadAsync. Il doit maintenant ressembler à ceci :It should now look like this:

    
    protected override async System.Threading.Tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)  
    {  
        await base.InitializeAsync(cancellationToken, progress);  
        this.AddService(typeof(STextWriterService), CreateTextWriterService);  
    
        ITextWriterService textService =   
           await this.GetServiceAsync(typeof(STextWriterService)) as ITextWriterService;  
    
        await textService.WriteLineAsync((<userpath>, "this is a test");  
    
        await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);  
        TestAsyncCommand.Initialize(this);
    }  
    
  3. Supprimer le Initialize() (méthode).Delete the Initialize() method.

  4. Dans le fichier TestAsyncCommand.cs, recherchez le MenuItemCallback() (méthode).In the TestAsyncCommand.cs file, find the MenuItemCallback() method. Supprimer le corps de la méthode.Delete the body of the method.

  5. Ajoutez une instruction using :Add a using statement:

    using System.IO;  
    
  6. Ajouter une méthode asynchrone nommée UseTextWriterAsync(), qui obtient le service et utilise ses méthodes :Add an asynchronous method named UseTextWriterAsync(), which gets the service and uses its methods:

    private async System.Threading.Tasks.Task UseTextWriterAsync()  
    {  
        // Query text writer service asynchronously to avoid a blocking call.
        ITextWriterService textService =   
           await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(STextWriterService))  
              as ITextWriterService;  
    
        // don't forget to change <userpath> to a local path  
        await textService.WriteLineAsync((<userpath>),"this is a test");  
       }  
    
  7. Appelez cette méthode à partir de la MenuItemCallback() méthode :Call this method from the MenuItemCallback() method:

    private void MenuItemCallback(object sender, EventArgs e)  
    {  
        UseTextWriterAsync();  
    }  
    
  8. Générez la solution et commencez le débogage.Build the solution and start debugging. Lorsque l’instance expérimentale de Visual Studio s’affiche, accédez à la outils menu, puis recherchez le TestAsyncCommand d’appeler élément de menu.When the experimental instance of Visual Studio appears, go to the Tools menu and look for the Invoke TestAsyncCommand menu item. Lorsque vous cliquez dessus, le TextWriterService écrit dans le fichier spécifié.When you click it, the TextWriterService writes to the file you specified. (Vous n’avez pas besoin d’ouvrir une solution, car l’appel de la commande entraîne également le package à charger.)(You don't need to open a solution, because invoking the command also causes the package to load.)

Voir aussiSee Also

Utilisation et fourniture de servicesUsing and Providing Services