From 014f30775af209e3d0b40e00ce452efd2574dae4 Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Thu, 19 Jun 2025 09:31:36 +1000 Subject: [PATCH 1/2] Document obtaining MEF components from projects In a chat with a partner team today I was looking for a doc to explain how to pull a MEF component from a project, when not a suitably-scoped MEF component yourself. This information is touched on in `finding_CPS_in_a_VS_project.md`, but feels more discoverable in `mef.md`. --- doc/overview/mef.md | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/doc/overview/mef.md b/doc/overview/mef.md index 185cfac..0263165 100644 --- a/doc/overview/mef.md +++ b/doc/overview/mef.md @@ -75,8 +75,10 @@ it could occasionally be out of sync with extensions. In this situation, running the following commands inside command-line window will reset the cache: - devenv /UpdateConfiguration - devenv /ClearCache +``` +devenv /UpdateConfiguration +devenv /ClearCache +``` VS MEF provides a detailed error report when it finds errors inside MEF compositions. It always tries to keep the rest of the components working by @@ -86,7 +88,9 @@ error report file will help to diagnose issues such as the reason why a certain component is never being loaded into VS. The error report file can be found at - [User]\AppData\Local\Microsoft\VisualStudio\[Version]\ComponentModelCache\Microsoft.VisualStudio.Default.err +``` +%LOCALAPPDATA%\Microsoft\VisualStudio\[Version]\ComponentModelCache\Microsoft.VisualStudio.Default.err +``` Because a MEF error may cause chains of errors in other components, one should always start with investigating level 1 composition errors. @@ -138,10 +142,10 @@ fact that the component carries the correct `AppliesTo` metadata. It is important to use the correct `AppliesTo` metadata when defining a component. Normally, the `AppliesTo` metadata is the new project type the component supports; in the advanced scenario, `AppliesTo` metadata can be an expression -like this -- +like this: ```csharp -[AppliesTo("MyLanaguageProject + DeviceProject")] +[AppliesTo("MyLanaguageProject & DeviceProject")] ``` Also, when a component exports additional properties or methods, the @@ -196,6 +200,36 @@ are provided by CPS and cannot be replaced by extensions. Such services include the `ConfiguredProject`, `UnconfiguredProject`, `IProjectLockService`, etc. +### Obtaining MEF components in project scopes + +As described in [scopes](scopes.md), MEF project-specific components instances +can exist in the scope of an `UnconfiguredProject` or a `ConfiguredProject`. + +If your component is a MEF part and in a compatible scope, then the best way +to obtain an instance is just to import it using a standard MEF import. + +However, if your component is not participating in MEF, or is in the global +or `ProjectService` scopes, then you can obtain project-scoped components +via the relevant instance of `UnconfiguredProject` or `ConfiguredProject`. + +Note that several key CPS services are available directly on via the project's +`Services` property. However if you need a MEF component that is not already +exposed this way, you can use the project's `ExportProvider` as follows. + +For example: + +```csharp +UnconfiguredProject unconfiguredProject = ...; +ConfiguredProject configuredProject = ...; + +IMyUnconfiguredComponent c1 = unconfiguredProject.Services.ExportProvider.GetExportedValue(); + +IMyConfiguredComponent c2 = configuredProject.Services.ExportProvider.GetExportedValue(); +``` + +For details on obtaining an instance of `UnconfiguredProject` or `ConfiguredProject`, +see [Finding CPS in a VS project](..\automation\finding_CPS_in_a_VS_project.md) + ## MEF and C# Nullable Reference Types When using the C# nullable feature in your code, you may need to tweak the above From 2bad03aa01c4a0ac50d19cf802b81239e82bf30c Mon Sep 17 00:00:00 2001 From: Drew Noakes Date: Thu, 19 Jun 2025 09:56:09 +1000 Subject: [PATCH 2/2] Fix dead links --- .../obtaining_the_MSBuild.Project_from_CPS.md | 17 +---------------- doc/overview/mef.md | 2 +- doc/overview/threading_model.md | 2 +- doc/overview/threading_rules.md | 2 +- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/doc/automation/obtaining_the_MSBuild.Project_from_CPS.md b/doc/automation/obtaining_the_MSBuild.Project_from_CPS.md index b1a4c0d..e559151 100644 --- a/doc/automation/obtaining_the_MSBuild.Project_from_CPS.md +++ b/doc/automation/obtaining_the_MSBuild.Project_from_CPS.md @@ -7,7 +7,6 @@ Obtaining the MSBuild.Project from CPS 3. Acquire a read, upgradeable read or write lock, as appropriate, and use the MSBuild Project object exclusively within the lock: -Visual Studio 2019 ```csharp await projectLockService.WriteLockAsync( async access => @@ -23,24 +22,10 @@ await projectLockService.WriteLockAsync( cancellationToken); ``` -Visual Studio 2017 and earlier -```csharp - using (var access = await projectLockService.WriteLockAsync()) - { - MSBuild.Project project = await access.GetProjectAsync(configuredProject); - - // Use the msbuild project, respecting the type of lock acquired. - - // If you're going to change the project in any way, - // check it out from SCC first: - await access.CheckoutAsync(configuredProject.UnconfiguredProject.FullPath); - } -``` - Note that it's important that you use `await`. Do not use `Task.Result` or `Task.Wait()` on these async methods or your code will malfunction and/or hang. If you must do this within a synchronous method, see [threading -rule #2](https://github.com/Microsoft/vs-threading/blob/master/doc/threading_rules.md#2-when-an-implementation-of-an-already-shipped-public-api-must-call). +rule #2](https://github.com/microsoft/vs-threading/blob/main/docfx/docs/threading_rules.md#-rule-2-use-jtfrun). **Please observe CPS [project locking rules](../overview/project_lock.md) by not retaining any references to MSBuild objects beyond the scope of the lock and diff --git a/doc/overview/mef.md b/doc/overview/mef.md index 0263165..eb23839 100644 --- a/doc/overview/mef.md +++ b/doc/overview/mef.md @@ -228,7 +228,7 @@ IMyConfiguredComponent c2 = configuredProject.Services.ExportProvider.GetExporte ``` For details on obtaining an instance of `UnconfiguredProject` or `ConfiguredProject`, -see [Finding CPS in a VS project](..\automation\finding_CPS_in_a_VS_project.md) +see [Finding CPS in a VS project](../automation/finding_CPS_in_a_VS_project.md) ## MEF and C# Nullable Reference Types diff --git a/doc/overview/threading_model.md b/doc/overview/threading_model.md index 589f2c6..02c78de 100644 --- a/doc/overview/threading_model.md +++ b/doc/overview/threading_model.md @@ -6,7 +6,7 @@ Rules](threading_rules.md) Important: **Do not call Task.Wait() or Task.Result in your code because these -violate [threading rule #2](https://github.com/Microsoft/vs-threading/blob/master/doc/threading_rules.md#2-when-an-implementation-of-an-already-shipped-public-api-must-call) and will often lead +violate [threading rule #2](https://github.com/microsoft/vs-threading/blob/main/docfx/docs/threading_rules.md#-rule-2-use-jtfrun) and will often lead to deadlocks.** Avoid use of `ThreadHelper.JoinableTaskFactory` as that does not have the intelligence diff --git a/doc/overview/threading_rules.md b/doc/overview/threading_rules.md index 1a09aea..bea770b 100644 --- a/doc/overview/threading_rules.md +++ b/doc/overview/threading_rules.md @@ -1,6 +1,6 @@ # The 3 Threading Rules -The 3 Threading Rules can now be found at [Microsoft/vs-threading/doc/threading_rules.md](https://github.com/Microsoft/vs-threading/blob/master/doc/threading_rules.md) +The 3 Threading Rules can now be found in the [microsoft/vs-threading repo](https://github.com/microsoft/vs-threading/blob/main/docfx/docs/threading_rules.md). # CPS Threading