Skip to content

Commit

Permalink
Lazily initialize global service provider and MEF components
Browse files Browse the repository at this point in the history
Otherwise, the previous approach can hang VS if the cache is being rebuilt
and we're requesting it synchronously from within the process start.

Note that unless MEF components are requested, we don't even initialize
the component model service at all either.

Fixes #34
  • Loading branch information
kzu committed Aug 23, 2022
1 parent f672bde commit 21b0b72
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 6 deletions.
12 changes: 7 additions & 5 deletions src/Xunit.Vsix/GlobalServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ namespace Xunit;
[EditorBrowsable(EditorBrowsableState.Never)]
public static class GlobalServiceProvider
{
static readonly IServiceProvider instance;
static readonly dynamic components;
static readonly System.IServiceProvider instance;
static readonly Lazy<dynamic> components;

static GlobalServiceProvider()
{
Expand All @@ -30,8 +30,10 @@ static GlobalServiceProvider()
else
{
instance = new OleServiceProvider(dte);
components = instance.GetService<Interop.SComponentModel, object>().AsDynamicReflection();
}

components = new Lazy<dynamic>(() =>
instance.GetService<Interop.SComponentModel, object>().AsDynamicReflection());
}
catch (NotSupportedException)
{
Expand Down Expand Up @@ -64,12 +66,12 @@ static GlobalServiceProvider()
/// <summary>
/// Retrieves an exported MEF component from the currently running Visual Studio.
/// </summary>
public static T GetExport<T>() => components == null ? null : components?.GetService<T>();
public static T GetExport<T>() => components == null ? null : components.Value?.GetService<T>();

/// <summary>
/// Retrieves exported MEF components from the currently running Visual Studio.
/// </summary>
public static IEnumerable<T> GetExports<T>() => components?.GetExtensions<T>() ?? Array.Empty<T>();
public static IEnumerable<T> GetExports<T>() => components.Value?.GetExtensions<T>() ?? Array.Empty<T>();

class NullServices : IServiceProvider
{
Expand Down
2 changes: 1 addition & 1 deletion src/Xunit.Vsix/VsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ bool Start()

// Retrieve the component model service, which could also now take time depending on new
// extensions being installed or updated before the first launch.
var components = services.GetService<Interop.SComponentModel, object>();
//var components = services.GetService<Interop.SComponentModel, object>();

//if (Debugger.IsAttached)
//{
Expand Down
5 changes: 5 additions & 0 deletions src/Xunit.Vsix/VsRemoteRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class VsRemoteRunner : MarshalByRefObject, IVsRemoteRunner
{
string _pipeName;
IChannel _channel;
IServiceProvider _services;

Dictionary<Type, object> _assemblyFixtureMappings = new Dictionary<Type, object>();
Dictionary<Type, object> _collectionFixtureMappings = new Dictionary<Type, object>();
Expand Down Expand Up @@ -55,6 +56,10 @@ public string[][] GetEnvironment()

public VsixRunSummary Run(VsixTestCase testCase, IMessageBus messageBus)
{
// Before the first test is run, ensure we have initialized the global services
// which in turn requests the component model which ensures MEF is initialized.
_services ??= GlobalServiceProvider.Default;

messageBus.QueueMessage(new DiagnosticMessage("Running {0}", testCase.DisplayName));

var aggregator = new ExceptionAggregator();
Expand Down

0 comments on commit 21b0b72

Please sign in to comment.