public override bool Execute() { if (Environment.GetEnvironmentVariable("CreateCompositionTaskDebug") == "1") { Debugger.Launch(); } this.catalogAssemblyPaths.AddRange(this.CatalogAssemblies.Select(this.GetMEFAssemblyFullPath)); AppDomain.CurrentDomain.AssemblyResolve += this.CurrentDomain_AssemblyResolve; try { var loadableAssemblies = this.catalogAssemblyPaths .Concat(this.ReferenceAssemblies.Select(i => i.GetMetadata("FullPath")) ?? Enumerable.Empty <string>()); var resolver = new Resolver(new AssemblyLoader(loadableAssemblies)); var discovery = PartDiscovery.Combine( new AttributedPartDiscoveryV1(resolver), new AttributedPartDiscovery(resolver, isNonPublicSupported: true)); this.CancellationToken.ThrowIfCancellationRequested(); var parts = discovery.CreatePartsAsync(this.catalogAssemblyPaths).GetAwaiter().GetResult(); var catalog = ComposableCatalog.Create(resolver) .AddParts(parts); this.LogLines(this.GetLogFilePath("CatalogAssemblies"), this.GetCatalogAssembliesLines(catalog), this.CancellationToken); string catalogErrorFilePath = this.GetLogFilePath("CatalogErrors"); if (catalog.DiscoveredParts.DiscoveryErrors.IsEmpty) { File.Delete(catalogErrorFilePath); } else { this.LogLines(catalogErrorFilePath, GetCatalogErrorLines(catalog), this.CancellationToken); foreach (var error in catalog.DiscoveredParts.DiscoveryErrors) { string message = error.GetUserMessage(); if (this.ContinueOnDiscoveryErrors) { this.LogWarning(DiscoveryErrorCode, message); } else { this.Log.LogError(null, DiscoveryErrorCode, null, null, 0, 0, 0, 0, message); } } if (!this.ContinueOnDiscoveryErrors) { return(false); } } this.CancellationToken.ThrowIfCancellationRequested(); var configuration = CompositionConfiguration.Create(catalog); if (!string.IsNullOrEmpty(this.DgmlOutputPath)) { configuration.CreateDgml().Save(this.DgmlOutputPath); this.writtenFiles.Add(this.DgmlOutputPath); } this.CancellationToken.ThrowIfCancellationRequested(); string compositionLogPath = this.GetLogFilePath("CompositionErrors"); if (configuration.CompositionErrors.IsEmpty) { File.Delete(compositionLogPath); } else { this.LogLines(compositionLogPath, GetCompositionErrorLines(configuration), this.CancellationToken); foreach (var error in configuration.CompositionErrors.Peek()) { if (this.ContinueOnCompositionErrors) { this.LogWarning(CompositionErrorCode, error.Message); } else { this.Log.LogError(null, CompositionErrorCode, null, null, 0, 0, 0, 0, error.Message); } } if (!this.ContinueOnCompositionErrors) { return(false); } } this.CancellationToken.ThrowIfCancellationRequested(); string cachePath = Path.GetFullPath(this.CompositionCacheFile); this.Log.LogMessage("Producing IoC container \"{0}\"", cachePath); using (var cacheStream = File.Open(cachePath, FileMode.Create)) { this.CancellationToken.ThrowIfCancellationRequested(); var runtime = RuntimeComposition.CreateRuntimeComposition(configuration); this.CancellationToken.ThrowIfCancellationRequested(); var runtimeCache = new CachedComposition(); runtimeCache.SaveAsync(runtime, cacheStream, this.CancellationToken).GetAwaiter().GetResult(); } this.writtenFiles.Add(cachePath); return(!this.Log.HasLoggedErrors); } finally { AppDomain.CurrentDomain.AssemblyResolve -= this.CurrentDomain_AssemblyResolve; this.FileWrites = this.writtenFiles.Select(f => new TaskItem(f)).ToArray(); } }
/// <summary> /// Creates a reusable environment that consists of /// 1) default parts and parts needed to bootstrap the editor, except for parts whose metadata matches these from <paramref name="typesThatOverride"></paramref> /// 2) parts found in the provided assemblies /// 3) parts found in the provided types. /// </summary> /// <param name="assembliesToLoad">Filenames of assemblies that will be searched for MEF parts.</param> /// <param name="typesToLoad">Types to include in the MEF catalog.</param> /// <param name="typesThatOverride">Types whose export signatures will be used to filter out the default catalog.</param> /// <returns>Composed environment that can be reused across tests</returns> public static async Task <EditorEnvironment> InitializeAsync(IEnumerable <string> assembliesToLoad, IEnumerable <Type> typesToLoad, IEnumerable <Type> typesThatOverride) { // Prepare part discovery to support both flavors of MEF attributes. var discovery = PartDiscovery.Combine( new AttributedPartDiscovery(Resolver.DefaultInstance, isNonPublicSupported: true), // "NuGet MEF" attributes (Microsoft.Composition) new AttributedPartDiscoveryV1(Resolver.DefaultInstance)); // ".NET MEF" attributes (System.ComponentModel.Composition) var assemblyCatalog = ComposableCatalog.Create(Resolver.DefaultInstance); // Create a list of parts that should override the defaults. Used for mocking when Import expects only one part. IEnumerable <ComposablePartDefinition> partsThatOverride = null; if (typesThatOverride != null) { partsThatOverride = (await discovery.CreatePartsAsync(typesThatOverride)).Parts; } // Load default parts foreach (var assemblyName in DefaultAssemblies) { try { var parts = (await discovery.CreatePartsAsync(Assembly.LoadFrom(assemblyName))).Parts; if (partsThatOverride != null) { // Exclude parts whose contract matches the contract of any of the overriding parts var overriddenParts = parts.Where(defaultPart => defaultPart.ExportedTypes.Any(defaultType => partsThatOverride.Any(overridingPart => overridingPart.ExportedTypes.Any(overridingType => overridingType.ContractName == defaultType.ContractName)))); parts = parts.Except(overriddenParts); } assemblyCatalog = assemblyCatalog.AddParts(parts); } catch (System.IO.FileNotFoundException) { // Note, if we provide inner exception, the MSTest runner will display it instead of informativeException. For this reason, we don't provide inner exception. var informativeException = new InvalidOperationException($"Required assembly `{assemblyName}` not found. Please place it in this process' working directory. You can do it by adding reference to the NuGet package that contains this assembly."); informativeException.Data["Missing file"] = assemblyName; throw informativeException; } } // Load parts from all types in the specified assemblies if (assembliesToLoad != null) { foreach (string assembly in assembliesToLoad) { var parts = await discovery.CreatePartsAsync(Assembly.LoadFrom(assembly)); assemblyCatalog = assemblyCatalog.AddParts(parts); } } // Load parts from the specified types if (typesToLoad != null) { var parts = await discovery.CreatePartsAsync(typesToLoad); assemblyCatalog = assemblyCatalog.AddParts(parts); } // TODO: see if this will be useful assemblyCatalog = assemblyCatalog.WithCompositionService(); // Makes an ICompositionService export available to MEF parts to import. // Assemble the parts into a valid graph. var compositionConfiguration = CompositionConfiguration.Create(assemblyCatalog); ImmutableArray <string> compositionErrors = ImmutableArray <string> .Empty; if (compositionConfiguration.CompositionErrors.Any()) { compositionErrors = compositionConfiguration.CompositionErrors.SelectMany(collection => collection.Select(diagnostic => diagnostic.Message)).ToImmutableArray(); // Uncomment to investigate errors and continue execution // Debugger.Break(); // Uncomment to fail immediately: // var exception = new InvalidOperationException("There were composition errors"); // exception.Data["Errors"] = errors; // throw exception; } // Prepare an ExportProvider factory based on this graph. // This factory can be now re-used across tests return(new EditorEnvironment(compositionConfiguration.CreateExportProviderFactory(), compositionErrors)); }
private static async Task InitializeMef() { // Add custom logic for resolution of dependencies. // This necessary because the AssemblyLoadContext.LoadFromAssemblyPath and related methods, // do not automatically load dependencies. AssemblyLoadContext.Default.Resolving += ResolvePluginDependencies; // Cannot show MessageBox here, because WPF would crash with a XamlParseException // Remember and show exceptions in text output, once MainWindow is properly initialized try { // Set up VS MEF. For now, only do MEF1 part discovery, since that was in use before. // To support both MEF1 and MEF2 parts, just change this to: // var discovery = PartDiscovery.Combine(new AttributedPartDiscoveryV1(Resolver.DefaultInstance), // new AttributedPartDiscovery(Resolver.DefaultInstance)); var discovery = new AttributedPartDiscoveryV1(Resolver.DefaultInstance); var catalog = ComposableCatalog.Create(Resolver.DefaultInstance); var pluginDir = Path.GetDirectoryName(typeof(App).Module.FullyQualifiedName); if (pluginDir != null) { foreach (var plugin in Directory.GetFiles(pluginDir, "*.Plugin.dll")) { var name = Path.GetFileNameWithoutExtension(plugin); try { var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(plugin); var parts = await discovery.CreatePartsAsync(asm); catalog = catalog.AddParts(parts); } catch (Exception ex) { StartupExceptions.Add(new ExceptionData { Exception = ex, PluginName = name }); } } } // Add the built-in parts var createdParts = await discovery.CreatePartsAsync(Assembly.GetExecutingAssembly()); catalog = catalog.AddParts(createdParts); // If/When the project switches to .NET Standard/Core, this will be needed to allow metadata interfaces (as opposed // to metadata classes). When running on .NET Framework, it's automatic. // catalog.WithDesktopSupport(); // If/When any part needs to import ICompositionService, this will be needed: // catalog.WithCompositionService(); var config = CompositionConfiguration.Create(catalog); ExportProviderFactory = config.CreateExportProviderFactory(); ExportProvider = ExportProviderFactory.CreateExportProvider(); // This throws exceptions for composition failures. Alternatively, the configuration's CompositionErrors property // could be used to log the errors directly. Used at the end so that it does not prevent the export provider setup. config.ThrowOnErrors(); } catch (CompositionFailedException ex) when(ex.InnerException is AggregateException agex) { foreach (var inner in agex.InnerExceptions) { StartupExceptions.Add(new ExceptionData { Exception = inner }); } } catch (Exception ex) { StartupExceptions.Add(new ExceptionData { Exception = ex }); } }
public App() { var cmdArgs = Environment.GetCommandLineArgs().Skip(1); App.CommandLineArguments = new CommandLineArguments(cmdArgs); if ((App.CommandLineArguments.SingleInstance ?? true) && !MiscSettingsPanel.CurrentMiscSettings.AllowMultipleInstances) { cmdArgs = cmdArgs.Select(FullyQualifyPath); string message = string.Join(Environment.NewLine, cmdArgs); if (SendToPreviousInstance("ILSpy:\r\n" + message, !App.CommandLineArguments.NoActivate)) { Environment.Exit(0); } } InitializeComponent(); if (!System.Diagnostics.Debugger.IsAttached) { AppDomain.CurrentDomain.UnhandledException += ShowErrorBox; Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException; } TaskScheduler.UnobservedTaskException += DotNet40_UnobservedTaskException; // Cannot show MessageBox here, because WPF would crash with a XamlParseException // Remember and show exceptions in text output, once MainWindow is properly initialized try { // Set up VS MEF. For now, only do MEF1 part discovery, since that was in use before. // To support both MEF1 and MEF2 parts, just change this to: // var discovery = PartDiscovery.Combine(new AttributedPartDiscoveryV1(Resolver.DefaultInstance), // new AttributedPartDiscovery(Resolver.DefaultInstance)); var discovery = new AttributedPartDiscoveryV1(Resolver.DefaultInstance); var catalog = ComposableCatalog.Create(Resolver.DefaultInstance); var pluginDir = Path.GetDirectoryName(typeof(App).Module.FullyQualifiedName); if (pluginDir != null) { foreach (var plugin in Directory.GetFiles(pluginDir, "*.Plugin.dll")) { var name = Path.GetFileNameWithoutExtension(plugin); try { var asm = Assembly.Load(name); var parts = discovery.CreatePartsAsync(asm).GetAwaiter().GetResult(); catalog = catalog.AddParts(parts); } catch (Exception ex) { StartupExceptions.Add(new ExceptionData { Exception = ex, PluginName = name }); } } } // Add the built-in parts catalog = catalog.AddParts(discovery.CreatePartsAsync(Assembly.GetExecutingAssembly()).GetAwaiter().GetResult()); // If/When the project switches to .NET Standard/Core, this will be needed to allow metadata interfaces (as opposed // to metadata classes). When running on .NET Framework, it's automatic. // catalog.WithDesktopSupport(); // If/When any part needs to import ICompositionService, this will be needed: // catalog.WithCompositionService(); var config = CompositionConfiguration.Create(catalog); exportProviderFactory = config.CreateExportProviderFactory(); exportProvider = exportProviderFactory.CreateExportProvider(); // This throws exceptions for composition failures. Alternatively, the configuration's CompositionErrors property // could be used to log the errors directly. Used at the end so that it does not prevent the export provider setup. config.ThrowOnErrors(); } catch (Exception ex) { StartupExceptions.Add(new ExceptionData { Exception = ex }); } Languages.Initialize(exportProvider); EventManager.RegisterClassHandler(typeof(Window), Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler(Window_RequestNavigate)); ILSpyTraceListener.Install(); }
public void Create() { Assert.Throws <ArgumentNullException>(() => ComposableCatalog.Create(null)); Assert.NotNull(ComposableCatalog.Create(Resolver.DefaultInstance)); }