Skip to content

Ban incompatible service provider extension methods#60276

Merged
sharwell merged 1 commit intodotnet:mainfrom
sharwell:service-extensions
Mar 20, 2022
Merged

Ban incompatible service provider extension methods#60276
sharwell merged 1 commit intodotnet:mainfrom
sharwell:service-extensions

Conversation

@sharwell
Copy link
Contributor

  • Ban use of incompatible service provider extensions (which use ThreadHelper.JoinableTaskFactory internally)
  • Implement new service provider extensions which include JoinableTaskFactory as a parameter
  • Update existing calls to use the new extension methods

@sharwell sharwell requested a review from a team as a code owner March 19, 2022 20:16
@sharwell sharwell requested a review from a team March 19, 2022 20:16
@sharwell sharwell requested a review from a team as a code owner March 19, 2022 20:16
@ghost ghost added the Area-IDE label Mar 19, 2022
/// </exception>
public static TInterface GetService<TService, TInterface>(
this IServiceProvider serviceProvider,
JoinableTaskFactory joinableTaskFactory)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have some extensions that also take an IThreadingContext instead of hte JTF?

Copy link
Contributor Author

@sharwell sharwell Mar 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer not. These are the extensions under consideration for future addition to the SDK, and matching signatures will make it easy to get used to this form and eventually remove the custom implementations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They can be in a different type :-). But I don't feel strongly. But it's more about the convenience for us.

{
await joinableTaskFactory.SwitchToMainThreadAsync();

var service = serviceProvider.GetService(typeof(TService));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this just call: GetServiceOnMainThread at this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. The error handling behavior is different.

GetServiceOnMainThread is a Roslyn-specific behavior. The IDE implementation of these GetService calls always use JTF.

[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public ServiceFactory(SVsServiceProvider serviceProvider)
=> _serviceProvider = (IAsyncServiceProvider)serviceProvider;
public ServiceFactory(SVsServiceProvider serviceProvider, IThreadingContext threadingContext)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm so confused about what pattern we're supposed to use for importating. i see some code actually importing IAsyncServiceProvider above, so i don't know why we'd use SVsServiceProvider .

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types are originally exported here:
https://devdiv.visualstudio.com/DevDiv/_git/VS-Platform?path=/src/Shell/MefHosting/ComponentModelHostImpl/VsComponentModelHostExporter.cs&version=GBmain&line=23&lineEnd=30&lineStartColumn=1&lineEndColumn=1&lineStyle=plain&_a=contents

The import strategy depends on whether you are using MEF 1 or MEF 2 attributes (MEF 1 is more expressive here).

await TaskScheduler.Default;

var componentModel = await AsyncServiceProvider.GlobalProvider.GetServiceAsync<SComponentModel, IComponentModel>().ConfigureAwait(false);
var componentModel = (IComponentModel?)await AsyncServiceProvider.GlobalProvider.GetServiceAsync(typeof(SComponentModel)).ConfigureAwait(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whis is this safe, if we're running in the bG? doesn't the cast have the same issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an old integration test outlier. It will eventually be removed by the migration to the new integration test project. In the meantime, it leverages the fact that IComponentModel is implemented by a managed service. If this was production code, I would require documentation that the SComponentModel service returns a free-threaded object before making this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a good catch. There were a couple other places where I switched to the non-generic form prior to adding RoslynServiceExtensions, so I audited the PR for those and will include the fixes in the next push.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good. :)

@sharwell sharwell force-pushed the service-extensions branch from 70e2598 to 798da18 Compare March 19, 2022 21:00
@sharwell sharwell requested a review from a team as a code owner March 19, 2022 21:00
@sharwell sharwell enabled auto-merge March 20, 2022 16:46
@sharwell sharwell merged commit 5f135a0 into dotnet:main Mar 20, 2022
@ghost ghost added this to the Next milestone Mar 20, 2022
@sharwell sharwell deleted the service-extensions branch March 21, 2022 16:15
@allisonchou allisonchou modified the milestones: Next, 17.2.P3 Mar 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants