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
Vytvořte projekt VSIX (Soubor>nový>projekt>Visual C#>Extensiblity>VSIX Project). Pojmenujte projekt TestAsync.
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.
V souboru TestAsyncPackage.cs změňte balíček tak, aby dědil místo
AsyncPackage
Package
:public sealed class TestAsyncPackage : AsyncPackage
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.
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.
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;
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í:
Do pole AllowsBackgroundLoading = true musíte přidat polePackageRegistrationAttribute, aby se zajistilo, že balíček lze inicializovat asynchronně. Další informace o PackageRegistrationAttribute najdete v tématu Registrace a zrušení registrace balíčků VSPackage.
Je nutné přidat pole IsAsyncQueryable = true do ProvideServiceAttribute pole, aby se zajistilo, že instance služby může být inicializována asynchronně.
Tady je příklad
AsyncPackage
registrace asynchronní služby:
[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
V souboru TestAsyncPackage.cs odeberte metodu
Initialize()
a přepište metoduInitializeAsync()
. 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);
Přidejte odkaz na Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll.
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.
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!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.
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.
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); }
Odstraňte metodu
Initialize()
.V souboru TestAsyncCommand.cs vyhledejte metodu
MenuItemCallback()
. Odstraňte tělo metody.Přidání direktivy using:
using System.IO;
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"); }
Volejte tuto metodu
MenuItemCallback()
z metody:private void MenuItemCallback(object sender, EventArgs e) { UseTextWriterAsync(); }
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.)