Aracılı hizmet kullanma
Bu belgede aracılı herhangi bir hizmetin alınması, genel kullanımı ve elden çıkarılmasıyla ilgili tüm kodlar, desenler ve uyarılar açıklanmaktadır. Satın alındıktan sonra belirli bir aracılı hizmeti kullanmayı öğrenmek için aracılı hizmetin belirli belgelerini arayın.
Bu belgedeki tüm kodlarla, C#'nin null atanabilir başvuru türleri özelliğinin etkinleştirilmesi kesinlikle önerilir.
IServiceBroker alma
Aracılı bir hizmet almak için önce bir örneğine IServiceBrokersahip olmanız gerekir. Kodunuz MEF (Yönetilen Genişletilebilirlik Çerçevesi) veya VSPackage bağlamında çalışırken genel hizmet aracısını istersiniz.
Aracılı hizmetler, hizmet fabrikaları çağrıldığında atandıkları hizmeti kullanmalıdırIServiceBroker.
Genel hizmet aracısı
Visual Studio, genel hizmet aracısını almak için iki yol sunar.
komutunuGetServiceAsync kullanarak GlobalProvideröğesini isteyinSVsBrokeredServiceContainer:
IBrokeredServiceContainer container = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SVsBrokeredServiceContainer, IBrokeredServiceContainer>();
IServiceBroker serviceBroker = container.GetFullAccessServiceBroker();
Visual Studio 2022'den başlayarak, MEF etkinleştirilmiş bir uzantıda çalışan kod genel hizmet aracısını içeri aktarabilir:
[Import(typeof(SVsFullAccessServiceBroker))]
IServiceBroker ServiceBroker { get; set; }
typeof
Import özniteliğinin gerekli olan bağımsız değişkenine dikkat edin.
Genel IServiceBroker için her istek, genel aracılı hizmet kapsayıcısına bir görünüm olarak hizmet veren bir nesnenin yeni bir örneğini oluşturur. Hizmet aracısının bu benzersiz örneği, istemcinizin bu istemcinin kullanımına özgü olayları almasına AvailabilityChanged olanak tanır. Uzantınızdaki her istemcinin/sınıfın bir örnek alıp tüm uzantınızda paylaşmak yerine yukarıdaki yaklaşımlardan birini kullanarak kendi hizmet aracısını almasını öneririz. Bu desen, aracılı bir hizmetin genel hizmet aracısını kullanmaması gereken güvenli kodlama desenlerini de teşvik eder.
Önemli
uygulamaları IServiceBroker genellikle uygulamaz IDisposable, ancak işleyiciler mevcutken AvailabilityChanged bu nesneler toplanamaz. Özellikle kodun işlem ömrü boyunca hizmet aracısını atabileceği durumlarda olay işleyicilerinin eklenmesi/kaldırılmasını dengelediğinizden emin olun.
Bağlama özgü hizmet aracıları
Uygun hizmet aracısını kullanmak, özellikle Live Share oturumları bağlamında aracılı hizmetlerin güvenlik modelinin önemli bir gereksinimidir.
Aracılı hizmetler kendileriyle IServiceBroker etkinleştirilir ve ile sunulan hizmetler Profferde dahil olmak üzere kendi aracılı hizmet gereksinimleri için bu örneği kullanmalıdır. Bu tür kod, BrokeredServiceFactory örneklenen aracılı hizmet tarafından kullanılacak bir hizmet aracısı alan bir sağlar.
Aracılı hizmet proxy'si alma
Aracılı hizmetin alınması genellikle yöntemiyle GetProxyAsync yapılır.
yöntemi, GetProxyAsync genel tür bağımsız değişkeni olarak bir ServiceRpcDescriptor ve hizmet arabirimi gerektirir. İstediğiniz aracılı hizmetle ilgili belgelerde tanımlayıcının nereden alınacağı ve hangi arabirimin kullanılacağı belirtilmelidir. Visual Studio'ya dahil edilen aracılı hizmetler için, kullanılacak arabirim tanımlayıcıdaki IntelliSense belgelerinde görünmelidir. Kullanılabilir Aracılı Hizmetleri Bulma bölümünde Visual Studio aracılı hizmetleri için tanımlayıcıları bulmayı öğrenin.
IServiceBroker broker; // Acquired as described earlier in this topic
IMyService? myService = await broker.GetProxyAsync<IMyService>(serviceDescriptor, cancellationToken);
using (myService as IDisposable)
{
Assumes.Present(myService); // Throw if service was not available
await myService.SayHelloAsync();
}
Tüm aracılı hizmet isteklerinde olduğu gibi, yukarıdaki kod aracılı hizmetin yeni bir örneğini etkinleştirir.
Hizmeti kullandıktan sonra, yürütme bloğundan çıktığı için yukarıdaki kod proxy'yi using
atacak.
Önemli
Hizmet arabiriminden IDisposabletüretilmese bile alınan her ara sunucu atılmalıdır.
Proxy'de genellikle atık toplanmasını engelleyen G/Ç kaynakları olduğundan atma önemlidir.
Yok etme, G/Ç'yi sonlandırarak proxy'nin çöp toplamasına izin verir.
Yok etmek IDisposable için için için bir koşullu atama kullanın ve gerçekten uygulamayan IDisposableproxy'ler veya proxy'ler için bir özel durumla karşılaşmamak için null
atamaya hazır olun.
Bu tür sızıntıları önlemeye yardımcı olmak için en son Microsoft.ServiceHub.Analyzers NuGet paketini yüklediğinizden ve ISBxxxx çözümleyici kurallarını etkin tuttuğunuzdan emin olun.
Proxy'nin atılması, bu istemciye ayrılmış aracılı hizmetin yok edilmesiyle sonuçlanır.
Kodunuz aracılı bir hizmet gerektiriyorsa ve hizmet kullanılabilir olmadığında çalışmasını tamamlayamazsa, özel durum oluşturmak yerine kod kullanıcı deneyimine sahipse kullanıcıya bir hata iletişim kutusu görüntüleyebilirsiniz.
İstemci RPC hedefleri
Bazı aracılı hizmetler "geri çağırmalar" için bir istemci RPC (Uzaktan Yordam Çağrısı) hedefi kabul eder veya gerektirir. Böyle bir seçenek veya gereksinim, söz konusu aracılı hizmetin belgelerinde bulunmalıdır. Visual Studio aracılı hizmetleri için bu bilgiler tanımlayıcıdaki IntelliSense belgelerine eklenmelidir.
Böyle bir durumda, istemci aşağıdaki gibi bir ServiceActivationOptions.ClientRpcTarget istemci sağlayabilir:
IMyService? myService = await broker.GetProxyAsync<IMyService>(
serviceDescriptor,
new ServiceActivationOptions
{
ClientRpcTarget = new MyCallbackObject(),
},
cancellationToken);
İstemci proxy'sini çağırma
Aracılı hizmet istemenin sonucu, bir ara sunucu tarafından uygulanan hizmet arabiriminin bir örneğidir. Bu ara sunucu, çağrıları ve olayları her yöne iletir ve hizmeti doğrudan çağırırken karşılaşabileceğiniz davranışlardan bazı önemli farklılıklar gösterir.
Gözlemci deseni
Hizmet sözleşmesi türündeki IObserver<T>parametreleri alıyorsa, gözlemci uygulama bölümünden böyle bir tür oluşturma hakkında daha fazla bilgi edinebilirsiniz.
uzantısı ActionBlock<TInput> yöntemiyle AsObserver uygulamak IObserver<T> için uyarlanabilir. Reactive çerçevesinin System.Reactive.Observer sınıfı, arabirimi kendiniz uygulamanın bir diğer alternatifidir.
Proxy'den özel durumlar oluştu
- Aracılı hizmetten oluşan özel durumlar için atılması beklenebilir RemoteInvocationException . Özgün özel durum içinde InnerExceptionbulunabilir.
Bu, uzaktan barındırılan bir hizmet için doğal bir davranıştır çünkü bu, 'den JsonRpcgelen bir davranıştır.
Hizmet yerel olduğunda, yerel proxy tüm özel durumları aynı şekilde kaydırarak istemci kodunun yerel ve uzak hizmetler için çalışan tek bir özel durum yoluna sahip olabilmesini sağlar.
- ErrorCode Hizmet belgelerinde dallayabileceğiniz belirli koşullara göre belirli kodların ayarlandığının belirtilip önerilmediğini denetleyin.
- daha geniş bir hata kümesi, için temel tür RemoteInvocationExceptionolan yakalanarak RemoteRpcExceptioniletilir.
- Uzak bir hizmete bağlantı bırakıldığında veya hizmeti barındıran işlem kilitlendiğinde herhangi bir çağrıdan atılması beklenir ConnectionLostException . Bu öncelikle hizmetin uzaktan ne zaman alınabileceğiyle ilgilidir.
Ara sunucuyu önbelleğe alma
Özellikle hizmet uzak bir işlemden geldiğinde aracılı bir hizmetin ve ilişkili proxy'nin etkinleştirilmesinde bazı masraflar vardır.
Aracılı hizmetin sık sık kullanılması, ara sunucuyu bir sınıfa yapılan birçok çağrıda önbelleğe almayı garanti ettiğinde, ara sunucu bu sınıftaki bir alanda depolanabilir.
İçeren sınıf atılabilir olmalı ve proxy'yi yönteminin içinde Dispose
atmalıdır.
Bu örneği ele alalım:
class MyExtension : IDisposable
{
readonly IServiceBroker serviceBroker;
IMyService? serviceProxy;
internal MyExtension(IServiceBroker serviceBroker)
{
this.serviceBroker = serviceBroker;
}
async Task SayHiAsync(CancellationToken cancellationToken)
{
if (this.serviceProxy is null)
{
this.serviceProxy = await this.serviceBroker.GetProxyAsync<IMyService>(serviceDescriptor, cancellationToken);
Assumes.Present(this.serviceProxy);
}
await this.serviceProxy.SayHelloAsync();
}
public void Dispose()
{
(this.serviceProxy as IDisposable)?.Dispose();
}
}
Yukarıdaki kod kabaca doğrudur, ancak ile SayHiAsync
arasındaki Dispose
yarış koşullarını hesaba eklemez.
Kod ayrıca daha önce alınan proxy'nin elden çıkarılmasına ve bir sonraki gerekli olduğunda ara sunucu talebine yol açması gereken olayları da hesaba AvailabilityChanged katmıyor.
ServiceBrokerClient sınıfı, kendi kodunuzu basit tutmaya yardımcı olmak için bu yarış ve geçersizleştirme koşullarını işlemek için tasarlanmıştır. Bu yardımcı sınıfı kullanarak ara sunucuyu önbelleğe alan bu güncelleştirilmiş örneği göz önünde bulundurun:
class MyExtension : IDisposable
{
readonly ServiceBrokerClient serviceBrokerClient;
internal MyExtension(IServiceBroker serviceBroker)
{
this.serviceBrokerClient = new ServiceBrokerClient(serviceBroker);
}
async Task SayHiAsync(CancellationToken cancellationToken)
{
using var rental = await this.serviceBrokerClient.GetProxyAsync<IMyService>(descriptor, cancellationToken);
Assumes.Present(rental.Proxy); // Throw if service is not available
IMyService myService = rental.Proxy;
await myService.SayHelloAsync();
}
public void Dispose()
{
// Disposing the ServiceBrokerClient will dispose of all proxies
// when their rentals are released.
this.serviceBrokerClient.Dispose();
}
}
Yukarıdaki kod, ve her bir ara sunucu kiralama işleminin ServiceBrokerClient atılmasından hala sorumludur. Yok etme ve ara sunucu kullanımı arasındaki yarış koşulları nesne tarafından ServiceBrokerClient işlenir; bu nesne, önbelleğe alınan her proxy'yi kendi elden çıkarma sırasında veya bu ara sunucu son kiralandığında (hangisi en son gerçekleşirse) atar.
ile ilgili önemli uyarılar ServiceBrokerClient
ServiceBrokerClient önbelleğe alınan proxy'leri yalnızca temel alarak dizinler ServiceMoniker . Geçirirseniz ServiceActivationOptions ve önbelleğe alınmış bir ara sunucu zaten kullanılabilir durumdaysa, önbelleğe alınan proxy kullanılmadan ServiceActivationOptionsdöndürülür ve hizmetten beklenmeyen davranışlar elde edilir. Bu gibi durumlarda doğrudan kullanmayı IServiceBroker göz önünde bulundurun.
'den ServiceBrokerClient.GetProxyAsync alınan öğesini ServiceBrokerClient.Rental<T> bir alanda depolamayın. Ara sunucu, tarafından bir yöntemin kapsamı dışında zaten önbelleğe alınmış durumdadır ServiceBrokerClient. Proxy'nin ömrü üzerinde daha fazla denetime ihtiyacınız varsa, özellikle de bir AvailabilityChanged olay nedeniyle talep konusunda, bunun yerine doğrudan kullanın IServiceBroker ve hizmet proxy'sini bir alanda depolayın.
Yerel değişken yerine bir alan oluşturup depolayın ServiceBrokerClient . Bunu bir yöntemde yerel değişken olarak oluşturur ve kullanırsanız, doğrudan kullanmaya IServiceBroker değer eklemez, ancak şimdi bir (hizmet) yerine iki nesneyi (istemci ve kiralama) atmanız gerekir.
IServiceBroker ile ServiceBrokerClient arasında seçim
Her ikisi de kullanıcı dostudur ve varsayılan değer büyük olasılıkla olmalıdır IServiceBroker.
Kategori | IServiceBroker | ServiceBrokerClient |
---|---|---|
Kullanıcı dostu | Yes | Yes |
Elden çıkarma gerektirir | Hayır | Evet |
Ara sunucu ömrünü yönetir | Hayır Sahip, proxy'yi kullandığında atmalıdır. | Evet, geçerli oldukları sürece canlı tutulurlar ve yeniden kullanılırlar. |
Durum bilgisi olmayan hizmetler için geçerlidir | Yes | Yes |
Durum bilgisi olan hizmetler için geçerlidir | Yes | Hayır |
Olay işleyicileri ara sunucuya eklendiğinde uygun | Yes | Hayır |
Eski ara sunucu geçersiz kılındığında bildirilecek olay | AvailabilityChanged | Invalidated |
ServiceBrokerClient bir ara sunucuyu hızlı ve sık sık yeniden kullanabilmeniz için kullanışlı bir araç sağlar. Burada, temel alınan hizmetin en üst düzey işlemler arasında sizin altınızdan değiştirilmesini önemsemezsiniz. Ancak bu şeyleri önemsiyorsanız ve proxy'lerinizin ömrünü kendiniz yönetmek istiyorsanız veya olay işleyicilerine ihtiyacınız varsa (bu, proxy'nin ömrünü yönetmeniz gerektiği anlamına gelir), kullanmanız IServiceBrokergerekir.
Hizmet kesintilerine dayanıklılık
Aracılı hizmetlerle mümkün olan birkaç tür hizmet kesintisi vardır:
- Hizmet kullanılamıyor.
- Daha önce alınan aracılı bir hizmete bırakılan bağlantı.
- Hizmetin kullanılabilirliğindeki bir değişiklik, gelecekte bu hizmet için bir istekte bulunulması gerekir.
Aracılı hizmet etkinleştirme hataları
Aracılı bir hizmet isteği kullanılabilir bir hizmet tarafından karşılanabiliyorsa ancak hizmet fabrikası işlenmeyen bir özel durum oluşturduğunda, hatayı anlayıp kullanıcıya bildirebilmeleri için istemciye geri bir ServiceActivationFailedException oluşturulur.
Aracılı bir hizmet isteği kullanılabilir herhangi bir hizmetle eşleştirilemiyorsa, null
istemciye döndürülür.
Böyle bir durumda, AvailabilityChanged hizmet daha sonra kullanılabilir olduğunda ve kullanılabilir olduğunda yükseltilecektir.
Hizmet isteği, hizmet orada olmadığından değil, sunulan sürüm istenen sürümden daha düşük olduğundan reddedilebilir. Geri dönüş planınız, istemcinizin var olduğunu bildiği ve etkileşim kurabildiği daha düşük sürümlerle hizmet isteğini yeniden denemeyi içerebilir.
Tüm başarısız sürüm denetimlerinin gecikme süresi fark edilebilir hale gelirse/olduğunda istemci, uzak bir kaynaktan hangi hizmetlerin ve sürümlerin kullanılabilir olduğu hakkında tam bir fikir edinmek için VisualStudioServices.VS2019_4Services.RemoteBrokeredServiceManifest isteğinde bulunabilir.
Bırakılan bağlantıları işleme
Başarıyla alınan aracılı hizmet proxy'si, bağlantının bırakılması veya onu barındıran işlemdeki kilitlenme nedeniyle başarısız olabilir. Böyle bir kesintiden sonra, söz konusu ara sunucuda yapılan tüm çağrılar ConnectionLostException oluşturulur.
Aracılı bir hizmet istemcisi, olayı işleyerek Disconnected bu tür bağlantı düşüşlerini proaktif olarak algılayabilir ve bunlara tepki verebilir. Bu olaya ulaşmak için, nesnesini almak JsonRpc için bir IJsonRpcClientProxy ara sunucu olarak atanmalıdır. Hizmet yerel olduğunda düzgün bir şekilde başarısız olmak için bu atama koşullu olarak yapılmalıdır.
if (this.myService is IJsonRpcClientProxy clientProxy)
{
clientProxy.JsonRpc.Disconnected += JsonRpc_Disconnected;
}
void JsonRpc_Disconnected(object? sender, JsonRpcDisconnectedEventArgs args)
{
if (args.Reason == DisconnectedReason.RemotePartyTerminated)
{
// consider reacquisition of the service.
}
}
Hizmet kullanılabilirliği değişikliklerini işleme
Aracılı hizmet istemcileri, olayı işleyerek daha önce sorguladıkları aracılı bir hizmeti ne zaman yeniden sorgulamaları gerektiğine ilişkin AvailabilityChanged bildirimler alabilir. Bu olaya yönelik işleyiciler, bir hizmet isteği yapıldıktan kısa süre sonra tetiklenen bir olayın yarış durumu nedeniyle kaybolmadığından emin olmak için aracılı bir hizmet istemeden önce eklenmelidir.
Aracılı bir hizmet yalnızca zaman uyumsuz bir yöntemin yürütülmesi süresi boyunca istendiğinde, bu olayın işlenmesi önerilmez. Olay en çok, ara sunucusunu uzun süreler boyunca depolayan istemciler için geçerlidir, böylece hizmet değişikliklerini telafi etmeleri gerekir ve proxy'lerini yenileyebilecek bir konumda olurlar.
Bu olay herhangi bir iş parçacığında, büyük olasılıkla olayın açıklayıcı olduğu bir hizmeti kullanan koda eş zamanlı olarak oluşturulabilir.
Aşağıdakiler dahil olmak üzere çeşitli durum değişiklikleri bu olayın oluşturulmasına neden olabilir:
- Açılan veya kapatılan bir çözüm veya klasör.
- Canlı Paylaşım oturumu başlatılıyor.
- Yeni bulunan dinamik olarak kaydedilmiş aracılı bir hizmet.
Etkilenen aracılı hizmet yalnızca bu olayın, isteğin yerine getirilip getirilmediğine bakılmaksızın daha önce bu hizmeti isteyen istemcilere yükseltilmesine neden olur.
Olay, söz konusu hizmet için yapılan her istek sonrasında hizmet başına en fazla bir kez oluşturulur. Örneğin, istemci A hizmetine istekte bulunursa ve B hizmeti kullanılabilirlik değişikliğiyle karşılaşırsa, bu istemciye hiçbir olay tetiklemez. Daha sonra, A hizmeti bir kullanılabilirlik değişikliğiyle karşılaştığında istemci olayı alır. İstemci A hizmetini yeniden istemezse, A için sonraki kullanılabilirlik değişiklikleri bu istemciye başka bildirim göndermez. İstemci yeniden A isteğinde bulunduktan sonra bu hizmetle ilgili bir sonraki bildirimi almaya uygun hale gelir.
Olay, bir hizmet kullanılabilir olduğunda, artık kullanılamadığında veya önceki tüm hizmet istemcilerinin hizmet için yeniden sorgulamasını gerektiren bir uygulama değişikliğiyle karşılaştığında tetiklenir.
Önbelleğe ServiceBrokerClient alınan proxy'lerle ilgili kullanılabilirlik değişikliği olaylarını, herhangi bir kiralama iade edildiğinde eski proxy'leri yok ederek ve sahibi istekte bulunup bulunmadığında hizmetin yeni bir örneğini isteyerek otomatik olarak işler. Bu sınıf, hizmet durum bilgisi olmadığında ve kodunuzun proxy'ye olay işleyicileri eklemesini gerektirmediğinde kodunuzu önemli ölçüde basitleştirebilir.
Aracılı hizmet kanalı alma
Aracılı hizmete ara sunucu aracılığıyla erişmek en yaygın ve kullanışlı teknik olsa da, gelişmiş senaryolarda istemcinin RPC'yi doğrudan denetleyebilmesi veya diğer veri türlerini doğrudan iletişim kurabilmesi için bu hizmete bir kanal istemek tercih edilebilir veya gerekli olabilir.
Aracılı hizmete bir boru yöntemiyle GetPipeAsync elde edilebilir. Tanımlayıcı tarafından sağlanan RPC davranışları gerekli olmadığından bu yöntem yerine ServiceRpcDescriptor bir alırServiceMoniker. Bir tanımlayıcınız olduğunda, özelliği aracılığıyla ServiceRpcDescriptor.Moniker bu tanımlayıcıdan bir ad edinebilirsiniz.
Kanallar G/Ç'ye bağlı olsa da çöp toplama için uygun değildir. Artık kullanılmayacak olan bu boruları her zaman tamamlayarak bellek sızıntılarından kaçının.
Aşağıdaki kod parçacığında aracılı bir hizmet etkinleştirilir ve istemcinin buna doğrudan bir kanalı vardır. İstemci daha sonra bir dosyanın içeriğini hizmete gönderir ve bağlantıyı keser.
async Task SendMovieAsync(string movieFilePath, CancellationToken cancellationToken)
{
IServiceBroker serviceBroker;
IDuplexPipe? pipe = await serviceBroker.GetPipeAsync(serviceMoniker, cancellationToken);
if (pipe is null)
{
throw new InvalidOperationException($"The brokered service '{serviceMoniker}' is not available.");
}
try
{
// Open the file optimized for async I/O
using FileStream fs = new FileStream(movieFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true);
await fs.CopyToAsync(pipe.Output.AsStream(), cancellationToken);
}
catch (Exception ex)
{
// Complete the pipe, passing through the exception so the remote side understands what went wrong.
await pipe.Input.CompleteAsync(ex);
await pipe.Output.CompleteAsync(ex);
throw;
}
finally
{
// Always complete the pipe after successfully using the service.
await pipe.Input.CompleteAsync();
await pipe.Output.CompleteAsync();
}
}
Aracılı hizmet istemcilerini test etme
Aracılı hizmetler, uzantınızı test ederken taklit etmek için makul bir bağımlılıktır. Aracılı bir hizmetle alay ederken, arabirimi sizin yerinize uygulayan ve istemcinizin çağıracağı belirli üyelere gereken kodu ekleyen bir sahte çerçeve kullanmanızı öneririz. Bu, üyeleri aracılı hizmet arabirimine eklendiğinde testlerinizin derlemeye ve kesme olmadan çalışmaya devam etmesini sağlar.
Uzantınızı test etmek için Microsoft.VisualStudio.Sdk.TestFramework kullanırken, testiniz istemci kodunuzun sorgulayıp çalıştırabileceği bir sahte hizmet sağlamak için standart kod içerebilir. Örneğin, testlerinizde VisualStudioServices.VS2022.FileSystem aracılı hizmetinin sahtesini yapmak istediğinizi varsayalım. Sahte kodu şu kodla gösterebilirsiniz:
IBrokeredServiceContainer sbc = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SVsBrokeredServiceContainer, IBrokeredServiceContainer>();
Mock<IFileSystem> mockFileSystem = new Mock<IFileSystem>();
sbc.Proffer(VisualStudioServices.VS2022.FileSystem, (ServiceMoniker moniker, ServiceActivationOptions options, IServiceBroker serviceBroker, CancellationToken cancellationToken) => new ValueTask<object?>(mockFileSystem.Object));
Sahte aracılı hizmet kapsayıcısı, Visual Studio'nun kendisinde olduğu gibi önce bir proffered hizmetinin kaydedilmesini gerektirmez.
Test altındaki kodunuz aracılı hizmeti normal şekilde alabilir, ancak test kapsamında Visual Studio altında çalışırken elde edeceği gerçek hizmet yerine sahtenizi alır:
IBrokeredServiceContainer sbc = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SVsBrokeredServiceContainer, IBrokeredServiceContainer>();
IServiceBroker serviceBroker = sbc.GetFullAccessServiceBroker();
IFileSystem? proxy = await serviceBroker.GetProxyAsync<IFileSystem>(VisualStudioServices.VS2022.FileSystem);
using (proxy as IDisposable)
{
Assumes.Present(proxy);
await proxy.DeleteAsync(new Uri("file://some/file"), recursive: false, null, this.TimeoutToken);
}