You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
To reduce the number of unnecessarily thread switches, we have introduced a new way to asynchronous retrieve services; IAsyncServiceProvider3.
/// <summary>/// Provides a mechanism for retrieving proffered services asynchronously. This is the async equivalent of <see cref="IServiceProvider"/>/// and should be used in asynchronous contexts to avoid blocking calling threads./// </summary>/// <remarks>/// <para>This interface is safe to access from any thread.</para>/// <para>Prefer this interface and <see cref="t:Microsoft.VisualStudio.Shell.ServiceExtensions" /> over using <see cref="IAsyncServiceProvider"/> and <see cref="IAsyncServiceProvider2"/> directly/// to avoid unexpected blocking RPC calls when casting the resulting service to a specific interface. The former also provide more consistent throwing behavior.</para>/// </remarks>publicinterfaceIAsyncServiceProvider3:IAsyncServiceProvider2{/// <summary>/// Retrieves a proffered service asynchronously, specifying whether to throw an exception if it could not be retrieved./// </summary>/// <typeparam name="TService">The service identity of the proffered service to retrieve.</typeparam>/// <typeparam name="TInterface">The interface used to interact with the proffered service. If <typeparamref name="TService"/> is not registered as async or free-threaded, then this cast will be performed on the main thread.</typeparam>/// <param name="throwOnFailure"><see langword="true"/> to throw an exception if the service could not be retrieved; otherwise, <see langword="false"/> to return <see langword="null"/> on failure.</param>/// <param name="cancellationToken">A token whose cancellation indicates that the caller no longer is interested in the result. This will not cancel the in-progress loading of packages and/or creation of services as a result of the service retrieval, but this token will result in an expediant cancellation of the returned Task.</param>/// <returns>A task representing the service retrieval whose result is the service or <see langword="null"/> if there was a failure and <paramref name="throwOnFailure"/> is <see langword="false"/>.</returns>/// <exception cref="OperationCanceledException">/// <paramref name="cancellationToken"/> has been canceled./// </exception>/// <exception cref="ServiceUnavailableException">/// <paramref name="throwOnFailure"/> is <see langword="true"/> and there was a failure retrieving the service due to one of the following conditions:/// <list type="bullet">/// <item>/// <description>The service threw an exception during activation. <see cref="Exception.InnerException"/> may include details about the underlying failure.</description>/// </item>/// <item>/// <description>The associated package failed to load. <see cref="Exception.InnerException"/> may include details about the underlying failure.</description>/// </item>/// <item>/// <description>The associated package could not be found, or the package did not correctly proffer the service.</description>/// </item>/// <item>/// <description>The associated package proffered <see langword="null"/>.</description>/// </item>/// <item>/// <description>The service does not support the requested interface specified by <typeparamref name="TInterface"/>.</description>/// </item>/// <item>/// <description>The environment has starting shutting down and the retrieval would have resulted in a package load.</description>/// </item>/// </list>/// </exception>/// <remarks>/// <para>Prefer this method over an explicit cast to <typeparamref name="TInterface"/> to avoid a blocking RPC call if the underlying service is STA-bound,/// which can hang if the UI thread is blocked in a <see cref="JoinableTaskFactory.Run(Func{Task})"/> or <see cref="JoinableTask.Join"/>.</para>/// <para>Note the difference in behavior this method has around exceptions to its non-generic equivalents <see cref="IAsyncServiceProvider.GetServiceAsync"/> and <see cref="IAsyncServiceProvider2.GetServiceAsync"/>.</para>/// <para>This method is safe to access from any thread.</para>/// </remarks>Task<TInterface?>GetServiceAsync<TService,TInterface>(boolthrowOnFailure,CancellationTokencancellationToken)whereTInterface:class;
This interface takes the throwing policy from ServiceExtensions.GetServiceAsync extensions methods, and brings into the global service provider and AsyncPackage. Unlike the extensions however, it only introduces a thread switch when absolutely required. Many operations are now free-threaded, and let's consumes cancel their observation of a package load and/or service creation.
varappId=awaitGetServiceAsync<SVsAppId,IVsAppId>();// Free-threaded and synchronous callvarservice=awaitGetServiceAsync<SManagedService,ManagedService>();// Free-threaded and synchronous call once service has been created.varservice=awaitGetServiecAsync<SSynchService,SyncService>(this.DisposalToken);// Not free-threaded (we will go to UI thread to grab SyncService), but we can now load `SyncService` package asynchronously, and let the user cancel its observation of it.
The intention of this interface is not to replace existing usage of IAsyncServiceProvider, in fact, almost all code inside Visual Studio immediately benefits from the very fact that all core APIs (ServiceExtensions, IVsService<TService, TInterface>, AsyncPackage.GetServiceAsync, SAsyncServiceProvider, now recognize and handle IAsyncServiceProvider3 without users changing code.
That is, except for Roslyn. Roslyn provides their own versions of the extensions so that they can plug in their own JoinableTaskFactory into the extensions, which was needed because they could not override ThreadHelper.JoinableTaskFactory.
This is now unneeded, simple implement IAsyncServiceProvider3 in your tests and you can control which JoinableTaskFactory to use to thread switch. ServiceExtensions will delegate to it if the IAsyncServiceProvider passed to is a IAsyncServiceProvider3.
The text was updated successfully, but these errors were encountered:
To reduce the number of unnecessarily thread switches, we have introduced a new way to asynchronous retrieve services; IAsyncServiceProvider3.
This interface takes the throwing policy from
ServiceExtensions.GetServiceAsync
extensions methods, and brings into the global service provider and AsyncPackage. Unlike the extensions however, it only introduces a thread switch when absolutely required. Many operations are now free-threaded, and let's consumes cancel their observation of a package load and/or service creation.The intention of this interface is not to replace existing usage of IAsyncServiceProvider, in fact, almost all code inside Visual Studio immediately benefits from the very fact that all core APIs (
ServiceExtensions
,IVsService<TService, TInterface>
,AsyncPackage.GetServiceAsync
,SAsyncServiceProvider
, now recognize and handle IAsyncServiceProvider3 without users changing code.That is, except for Roslyn. Roslyn provides their own versions of the extensions so that they can plug in their own JoinableTaskFactory into the extensions, which was needed because they could not override ThreadHelper.JoinableTaskFactory.
This is now unneeded, simple implement IAsyncServiceProvider3 in your tests and you can control which JoinableTaskFactory to use to thread switch. ServiceExtensions will delegate to it if the
IAsyncServiceProvider
passed to is aIAsyncServiceProvider3
.The text was updated successfully, but these errors were encountered: