Comment : fournir un service de Visual Studio asynchroneHow to: Provide an asynchronous Visual Studio service

Si vous souhaitez obtenir un service sans bloquer le thread d’interface utilisateur, vous devez créer 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 au lieu d’un Package, ajoutez le service avec les méthodes asynchrones spéciale du package asynchrone.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émenter un service asynchroneImplement an asynchronous service

  1. Créez un projet VSIX (fichier > New > projet > Visual C# > Extensibilité > 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 > un 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, modifier le package d’hériter de AsyncPackage plutôt que 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:

    • Une 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 car ils sont utilisés uniquement pour l’interrogation du 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 inclut 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 très basique 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 de 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);  
    }  
    

Inscrire un serviceRegister 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érente de l’inscription d’un service synchrone, vous devez vous assurer que 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 champ la PackageRegistrationAttribute pour vous assurer de package peut être initialisé de façon asynchrone pour plus d’informations sur la PackageRegistrationAttribute, consultez inscrire et Annuler 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 Register and unregister VSPackages.

  • Vous devez ajouter le IsAsyncQueryable = true champ la ProvideServiceAttribute pour garantir l’instance de service peut être initialisée 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  
{. . . }  

Ajouter un serviceAdd 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;
    }  
    

Utiliser un serviceUse a service

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

  1. Nous allons le montrer 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 qui a du sens 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 pour charger automatiquement.This causes the AsyncPackage to autoload. Lors de l’initialiseur est exécuté, vous devez trouver un fichier dans l’emplacement spécifié.When the initializer has run, you should find a file in the location you specified.

Utiliser un service asynchrone dans un gestionnaire de commandesUse 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 présentée ici 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 du projet, avec le bouton droit, puis sélectionnez ajouter > un nouvel élément > Extensibilité > commande personnalisée.) 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 à la TestAsyncPackage.cs fichier 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 le Initialize() (méthode), 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 dans le InitializeAsync() méthode dans le AsyncPackageForService.cs fichier.Move this line to the InitializeAsync() method in the AsyncPackageForService.cs file. Dans la mesure où il s’agit une initialisation asynchrone, vous devez basculer vers le thread principal avant l’initialisation de la commande à l’aide 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 TestAsyncCommand.cs de fichiers, 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. Ajoutez 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 et recherchez le TestAsyncCommand 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

Utilisez et fournir des servicesUse and provide services