Daniel Cazzulino: How to nuke the Visual Studio MEF component model cache from an MSI
A quick search on the web for InvalidMEFCacheException
will yield quite a few results. If you have faced it, you know it’s annoying like hell.
I wonder, if VS already detected its cache is invalid, which doesn’t it auto-nuke it and offer a quick Restart action?
Two very common ways you can corrupt the MEF cache are:
- Improperly include VS assemblies that provide MEF components in your extension
- Providing different versions of your own assemblies that provide MEF components in different extensions
The first issue can be solved easily by installing the
nuget package into your project. Sometimes some assemblies are missing from the suppression,
but the team is super responsive and will ship an updated nuget package the moment you report
the missing suppression in their gitter chat.
That’s one of the many benefits of shipping granular nuget packages out of band :).
If you want to be 100% future-proof, you can add this target to your VSIX project and be sure
that no missing assemblies ever go into your VSIX:
<Target Name="ExcludeVisualStudioAssemblies" AfterTargets="GetVsixSourceItems" BeforeTargets="RemoveVSSDKAssemblies" Condition="'$(IncludeCopyLocalReferencesInVSIXContainer)' == 'true'"> <ItemGroup> <SuppressPackaging Include="@(VSIXSourceItem)" Condition="$([System.String]::new('%(Filename)').StartsWith('Microsoft.VisualStudio'))" /> </ItemGroup> </Target>
The second case will require you to carefully factor your assemblies so that the actual MEF implementations
live in a single place and are distributed by a single extension, possibly declaring a dependeny on that one
in the other extensions’ manifests.
If users continue to see random (and usually hard to repro) MEF exceptions, it might be that it’s not you who
is distributing those duplicate assemblies, and with VS vibrant ecosystem of extensions, it’s hard to make sure
in advance that doesn’t ever happen. In that case, you might still want to ensure a clean MEF cache on the next
VS start after you install your product.
If you’re installing via the VS gallery as a VSIX, then you’re out of luck ;). But if you have an MSI that
installs your extension, then it’s fairly straightforward.
Partially based on the (fairly old) blog post tactical directory nukes,
I came up with the following, which works great:
- Add the WixUtilExtension to your WiX project.
I usually add it like this directly to the
<WixExtension Include="WixUtilExtension"> <HintPath>$(WixExtDir)WixUtilExtension.dll</HintPath> <Name>WixUtilExtension</Name> </WixExtension>
Add the XML namespace to your WiX file:
Declare and initialize a property for each of the VS MEF caches you support and are going to potentially clean:
<SetProperty Id="MEF14" Value="[%LOCALAPPDATA]MicrosoftVisualStudio14.0ComponentModelCache" Before="CostInitialize" />
- Finally, add the following element to a component installed by each VS version you support:
<util:RemoveFolderEx On="both" Property="MEF14" Id="CleanMEF14" />
Of course, have as many
MEF[n]properties as you need, like
MEF12, etc., and initialize
the property to point to the right ComponentModelCache folder appropriately.
On="both" ensures you clean the cache after an install or uninstall, so you always leave VS
in a pristine MEF state. The slight performance hit on the first run after an install is not terrible
and certainly a rare event unless you’re testing VS extensions for a living 😉