Sdílet prostřednictvím


Poskytnutí asynchronní služby sady Visual Studio

Pokud chcete získat službu bez blokování vlákna uživatelského rozhraní, měli byste vytvořit asynchronní službu a načíst balíček do vlákna na pozadí. Pro tento účel můžete použít AsyncPackage místo a Packagepřidat službu se speciálními asynchronními metodami balíčku.

Informace o poskytování synchronních služeb sady Visual Studio naleznete v tématu Postupy: Poskytování služby.

Implementace asynchronní služby

  1. Vytvořte projekt VSIX (Soubor>nový>projekt>Visual C#>Extensiblity>VSIX Project). Pojmenujte projekt TestAsync.

  2. Přidejte do projektu balíček VSPackage. Vyberte uzel projektu v Průzkumník řešení a klikněte na Přidat>novou položku>Visual C# Items>Extensibility>Visual Studio Package. Pojmenujte tento soubor TestAsyncPackage.cs.

  3. V souboru TestAsyncPackage.cs změňte balíček tak, aby dědil místo AsyncPackage Package:

    public sealed class TestAsyncPackage : AsyncPackage
    
  4. Pokud chcete implementovat službu, musíte vytvořit tři typy:

    • Rozhraní, které identifikuje službu. Mnoho z těchto rozhraní je prázdných, to znamená, že nemají žádné metody, protože se používají pouze k dotazování služby.

    • Rozhraní, které popisuje rozhraní služby. Toto rozhraní zahrnuje metody, které se mají implementovat.

    • Třída, která implementuje službu i rozhraní služby.

  5. Následující příklad ukazuje velmi základní implementaci těchto tří typů. Konstruktor třídy služby musí nastavit poskytovatele služeb. V tomto příkladu jenom přidáme službu do souboru kódu balíčku.

  6. Do souboru balíčku přidejte následující direktivy using:

    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. Tady je asynchronní implementace služby. Všimněte si, že v konstruktoru musíte nastavit asynchronního poskytovatele služeb, nikoli synchronního poskytovatele služeb:

    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 ThreadHelper.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);
    }
    

Registrace služby

Pokud chcete zaregistrovat službu, přidejte ProvideServiceAttribute ji do balíčku, který službu poskytuje. Pokud se liší od registrace synchronní služby, musíte zajistit, aby balíček i služba podporovaly asynchronní načítání:

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

Přidat službu

  1. V souboru TestAsyncPackage.cs odeberte metodu Initialize() a přepište metodu InitializeAsync() . Přidejte službu a přidejte metodu zpětného volání pro vytvoření služeb. Tady je příklad asynchronního inicializátoru, který přidává službu:

    protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
    {
        await base.InitializeAsync(cancellationToken, progress);
        this.AddService(typeof(STextWriterService), CreateTextWriterService);
    }
    
    

    Pokud chcete, aby byla tato služba viditelná mimo tento balíček, nastavte hodnotu příznaku zvýšení úrovně na true jako poslední parametr: this.AddService(typeof(STextWriterService), CreateTextWriterService, true);

  2. Přidejte odkaz na Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll.

  3. Implementujte metodu zpětného volání jako asynchronní metodu, která vytvoří a vrátí službu.

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

Použití služby

Teď můžete službu získat a používat její metody.

  1. Zobrazíme to v inicializátoru, ale službu můžete získat kdekoli, kde chcete službu používat.

    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;
        string userpath = @"C:\MyDir\MyFile.txt";
        await textService.WriteLineAsync(userpath, "this is a test");
    }
    
    

    Nezapomeňte změnit userpath název souboru a cestu, která dává smysl na vašem počítači!

  2. Sestavte a spusťte kód. Jakmile se zobrazí experimentální instance sady Visual Studio, otevřete řešení. To způsobí AsyncPackage automatické načítání. Po spuštění inicializátoru byste měli najít soubor v zadaném umístění.

Použití asynchronní služby v obslužné rutině příkazu

Tady je příklad použití asynchronní služby v příkazu nabídky. Pomocí zde uvedeného postupu můžete službu použít v jiných nesynchronních metodách.

  1. Přidejte do projektu příkaz nabídky. (V Průzkumník řešení vyberte uzel projektu, klikněte pravým tlačítkem myši a vyberte Přidat vlastní příkaz Rozšiřitelnost>>nové položky>.) Pojmenujte soubor příkazu TestAsyncCommand.cs.

  2. Vlastní šablona příkazu znovu přidá metodu Initialize() do souboru TestAsyncPackage.cs , aby se příkaz inicializoval. Initialize() V metodě zkopírujte řádek, který inicializuje příkaz. Měl by vypadat takto:

    TestAsyncCommand.Initialize(this);
    

    Přesuňte tento řádek do InitializeAsync() metody v souboru AsyncPackageForService.cs . Vzhledem k tomu, že se jedná o asynchronní inicializaci, musíte před inicializací příkazu pomocí SwitchToMainThreadAsyncpříkazu přepnout na hlavní vlákno . Teď by to mělo vypadat takto:

    
    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;
    
        string userpath = @"C:\MyDir\MyFile.txt";
        await textService.WriteLineAsync(userpath, "this is a test");
    
        await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
        TestAsyncCommand.Initialize(this);
    }
    
    
  3. Odstraňte metodu Initialize() .

  4. V souboru TestAsyncCommand.cs vyhledejte metoduMenuItemCallback(). Odstraňte tělo metody.

  5. Přidání direktivy using:

    using System.IO;
    
  6. Přidejte asynchronní metodu s názvem UseTextWriterAsync(), která získá službu a používá její metody:

    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;
    
        string userpath = @"C:\MyDir\MyFile.txt";
        await textService.WriteLineAsync(userpath, "this is a test");
       }
    
    
  7. Volejte tuto metodu MenuItemCallback() z metody:

    private void MenuItemCallback(object sender, EventArgs e)
    {
        UseTextWriterAsync();
    }
    
    
  8. Sestavte řešení a spusťte ladění. Když se zobrazí experimentální instance sady Visual Studio, přejděte do nabídky Nástroje a vyhledejte položku nabídky Invoke TestAsyncCommand . Když na něj kliknete, TextWriterService zapíše do zadaného souboru. (Nemusíte otevírat řešení, protože vyvolání příkazu také způsobí načtení balíčku.)