diff --git a/src/AvalonStudio.Shell.Extensibility/AvalonStudio.Shell.Extensibility.csproj b/src/AvalonStudio.Shell.Extensibility/AvalonStudio.Shell.Extensibility.csproj index 122ebb4..7fd94ca 100644 --- a/src/AvalonStudio.Shell.Extensibility/AvalonStudio.Shell.Extensibility.csproj +++ b/src/AvalonStudio.Shell.Extensibility/AvalonStudio.Shell.Extensibility.csproj @@ -11,6 +11,7 @@ + diff --git a/src/AvalonStudio.Shell.Extensibility/IoC.cs b/src/AvalonStudio.Shell.Extensibility/IoC.cs index ad7071b..50190ff 100644 --- a/src/AvalonStudio.Shell.Extensibility/IoC.cs +++ b/src/AvalonStudio.Shell.Extensibility/IoC.cs @@ -1,19 +1,19 @@ using System; using System.Collections.Generic; -using System.Composition.Hosting; using System.Linq; +using Microsoft.VisualStudio.Composition; namespace AvalonStudio.Extensibility { public static class IoC { - private static CompositionHost s_compositionHost; + private static ExportProvider s_exportProvider; public static object Get(Type t, string contract = null) { - if (s_compositionHost != null) + if (s_exportProvider != null) { - return s_compositionHost.GetExport(t, contract); + return s_exportProvider.AsExportProvider().GetExports(t, null, contract).SingleOrDefault(); } return default; @@ -21,9 +21,9 @@ public static object Get(Type t, string contract = null) public static T Get(string contract) { - if (s_compositionHost != null) + if (s_exportProvider != null) { - return s_compositionHost.GetExport(contract); + return s_exportProvider.GetExportedValue(contract); } return default; @@ -31,9 +31,9 @@ public static T Get(string contract) public static T Get() { - if (s_compositionHost != null) + if (s_exportProvider != null) { - return s_compositionHost.GetExport(); + return s_exportProvider.GetExportedValue(); } return default; @@ -41,9 +41,9 @@ public static T Get() public static IEnumerable GetInstances() { - if (s_compositionHost != null) + if (s_exportProvider != null) { - return s_compositionHost.GetExports(); + return s_exportProvider.GetExportedValues(); } return Enumerable.Empty(); @@ -51,17 +51,17 @@ public static IEnumerable GetInstances() public static IEnumerable GetInstances(string contract) { - if (s_compositionHost != null) + if (s_exportProvider != null) { - return s_compositionHost.GetExports(contract); + return s_exportProvider.GetExportedValues(contract); } return Enumerable.Empty(); } - public static void Initialise(CompositionHost host) + public static void Initialise(ExportProvider exportProvider) { - s_compositionHost = host; + s_exportProvider = exportProvider; } } } \ No newline at end of file diff --git a/src/AvalonStudio.Shell/AvalonStudio.Shell.csproj b/src/AvalonStudio.Shell/AvalonStudio.Shell.csproj index 9f9cc7b..e8e1295 100644 --- a/src/AvalonStudio.Shell/AvalonStudio.Shell.csproj +++ b/src/AvalonStudio.Shell/AvalonStudio.Shell.csproj @@ -14,6 +14,7 @@ + diff --git a/src/AvalonStudio.Shell/CompositionRoot.cs b/src/AvalonStudio.Shell/CompositionRoot.cs index e1b299e..5f17b36 100644 --- a/src/AvalonStudio.Shell/CompositionRoot.cs +++ b/src/AvalonStudio.Shell/CompositionRoot.cs @@ -1,29 +1,88 @@ using AvalonStudio.Extensibility; using AvalonStudio.Extensibility.Utils; +using Microsoft.VisualStudio.Composition; using System.Collections.Generic; -using System.Composition.Convention; -using System.Composition.Hosting; +using System.IO; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; namespace AvalonStudio { public static class CompositionRoot { - public static CompositionHost CreateContainer(ExtensionManager extensionManager) + public static async Task CreateExportProviderAsync( + ExtensionManager extensionManager, + CancellationToken cancellationToken = default) { - var conventions = new ConventionBuilder(); - conventions.ForTypesDerivedFrom().Export(); - - // TODO AppDomain here is a custom appdomain from namespace AvalonStudio.Extensibility.Utils. It is able - // to load any assembly in the bin directory (so not really appdomain) we need to get rid of this - // once all our default extensions are published with a manifest and copied to extensions dir. - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - var extensionAssemblies = LoadMefComponents(extensionManager); - - var configuration = new ContainerConfiguration() - .WithAssemblies(assemblies, conventions) - .WithAssemblies(extensionAssemblies); - return configuration.CreateContainer(); + var resolver = Resolver.DefaultInstance; + + ComposableCatalog catalog; + + var cachedCatalog = new CachedCatalog(); + + var cacheIsValid = false; + var cachePath = ""; + + if (cacheIsValid) + { + using (var cacheStream = File.OpenRead(cachePath)) + { + catalog = await cachedCatalog.LoadAsync(cacheStream, resolver, cancellationToken); + } + } + else + { + var discovery = new AttributedPartDiscovery(resolver, true); + + // TODO AppDomain here is a custom appdomain from namespace AvalonStudio.Extensibility.Utils. It is able + // to load any assembly in the bin directory (so not really appdomain) we need to get rid of this + // once all our default extensions are published with a manifest and copied to extensions dir. + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var extensionAssemblies = LoadMefComponents(extensionManager); + + catalog = ComposableCatalog.Create(resolver) + .AddParts(await discovery.CreatePartsAsync(assemblies).ConfigureAwait(false)) + .AddParts(await discovery.CreatePartsAsync(extensionAssemblies).ConfigureAwait(false)); + + // TODO: cache catalog + //using (var cacheStream = File.OpenWrite(cachePath)) + //{ + // await cachedCatalog.SaveAsync(catalog, cacheStream, cancellationToken); + //} + } + + var configuration = CompositionConfiguration.Create(catalog); + + // TODO: log errors to file + + var compositionErrors = configuration.CompositionErrors; + + while (!compositionErrors.IsEmpty) + { + var error = compositionErrors.Peek(); + + System.Console.WriteLine(); + System.Console.WriteLine("Composition Error:"); + System.Console.WriteLine(); + + foreach (var entry in error) + { + System.Console.WriteLine(entry.Message); + + foreach (var part in entry.Parts) + { + System.Console.WriteLine($" Part: {part.Definition.Id}"); + } + } + + compositionErrors = compositionErrors.Pop(); + } + + var exportProviderFactory = configuration.CreateExportProviderFactory(); + var exportProvider = exportProviderFactory.CreateExportProvider(); + + return exportProvider; } private static IEnumerable LoadMefComponents(ExtensionManager extensionManager) diff --git a/src/AvalonStudio.Shell/Shell.cs b/src/AvalonStudio.Shell/Shell.cs index c4eb2fd..bf6005e 100644 --- a/src/AvalonStudio.Shell/Shell.cs +++ b/src/AvalonStudio.Shell/Shell.cs @@ -17,7 +17,8 @@ public static class Shell Platform.Initialise(); var extensionManager = new ExtensionManager(); - var container = CompositionRoot.CreateContainer(extensionManager); + // we shouldn't do this, instead a progress dialog should be shown + var container = CompositionRoot.CreateExportProviderAsync(extensionManager).Result; IoC.Initialise(container); diff --git a/src/Packages.targets b/src/Packages.targets index df65112..7586e41 100644 --- a/src/Packages.targets +++ b/src/Packages.targets @@ -7,6 +7,7 @@ + diff --git a/src/Versions.props b/src/Versions.props index 1fde0d5..7745069 100644 --- a/src/Versions.props +++ b/src/Versions.props @@ -3,6 +3,7 @@ 0.6.2-build536 0.6.2-build5984-beta + 15.8.98 10.0.3 8.0.1