Example #1
0
        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();
            }
        }
Example #2
0
        /// <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));
        }
Example #3
0
        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
                });
            }
        }
Example #4
0
        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));
        }