コード例 #1
0
        /// <summary>
        /// Test if the source should be written to the destination (true) or if the destination is newer/same (false)
        /// </summary>
        /// <param name="source">AssemblyLocationInformation</param>
        /// <param name="destination">string with destination path</param>
        /// <returns>bool</returns>
        private bool ShouldWrite(AssemblyLocationInformation source, string destination)
        {
            if (source.Filename.Equals(destination))
            {
                return(false);
            }
            string path = Path.GetDirectoryName(destination);

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(FileLocations.AddonsLocation);
            }

            if (!File.Exists(destination))
            {
                return(true);
            }

            if (File.GetLastWriteTime(destination) >= source.FileDate)
            {
                return(false);
            }

            Log.Warn().WriteLine("Overwriting {0} with {1}, as the later is newer.", destination, source.Filename);
            File.Delete(destination);
            return(true);
        }
コード例 #2
0
        /// <summary>
        /// Logic to load an embedded assembly
        /// </summary>
        /// <param name="assemblyLocationInformation"></param>
        /// <returns>Assembly</returns>
        private Assembly LoadEmbeddedAssembly(AssemblyLocationInformation assemblyLocationInformation)
        {
            if (!assemblyLocationInformation.IsEmbedded)
            {
                return(null);
            }

            // Check if we can work with temporary files
            if (_applicationConfig.CopyEmbeddedAssembliesToFileSystem)
            {
                var assembly = LoadEmbeddedAssemblyViaTmpFile(assemblyLocationInformation);
                if (assembly != null)
                {
                    return(assembly);
                }
            }

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Loading {0} internally, this COULD cause assembly load context issues...", assemblyLocationInformation.Name);
            }
            using (var stream = Resources.AbsoluteResourceAsStream(assemblyLocationInformation.ContainingAssembly, assemblyLocationInformation.Filename))
            {
                return(Assembly.Load(stream.ToByteArray()));
            }
        }
コード例 #3
0
        /// <summary>
        /// This is a workaround where an embedded assembly is written to a tmp file, which solves some issues
        /// </summary>
        /// <param name="assemblyLocationInformation">AssemblyLocationInformation</param>
        /// <returns>Assembly</returns>
        private Assembly LoadEmbeddedAssemblyViaTmpFile(AssemblyLocationInformation assemblyLocationInformation)
        {
            var assemblyFileName = $@"{FileLocations.AddonsLocation}\{assemblyLocationInformation.Name}.dll";

            using (var stream = Resources.AbsoluteResourceAsStream(assemblyLocationInformation.ContainingAssembly, assemblyLocationInformation.Filename))
            {
                try
                {
                    if (ShouldWrite(assemblyLocationInformation, assemblyFileName))
                    {
                        using (var fileStream = new FileStream(assemblyFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                        {
                            stream.CopyTo(fileStream);
                        }
                        // Register delete on exit, this is done by calling a command
                        _assembliesToDeleteAtExit.Add(assemblyFileName);
                    }

                    // Get the assembly name from the file
                    var assemblyName = AssemblyName.GetAssemblyName(assemblyFileName);
                    if (Log.IsVerboseEnabled())
                    {
                        Log.Verbose().WriteLine("Loading {0} from {1}", assemblyLocationInformation.Name, assemblyFileName);
                    }
                    // Use load, as it's now in the probing path
                    return(Assembly.Load(assemblyName));
                }
                catch (Exception)
                {
                    stream.Seek(0, SeekOrigin.Begin);
                    var appdataDirectory = $@"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\{_applicationConfig.ApplicationName}";
                    assemblyFileName = $@"{appdataDirectory}\{assemblyLocationInformation.Name}.dll";
                    if (ShouldWrite(assemblyLocationInformation, assemblyFileName))
                    {
                        using (var fileStream = new FileStream(assemblyFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
                        {
                            stream.CopyTo(fileStream);
                        }
                        // Register delete on exit, this is done by calling a command
                        _assembliesToDeleteAtExit.Add(assemblyFileName);
                    }

                    if (Log.IsVerboseEnabled())
                    {
                        Log.Verbose().WriteLine("Loading {0} from {1}", assemblyLocationInformation.Name, assemblyFileName);
                    }
                    // Use load-from, as it's on a different place
                    return(Assembly.LoadFrom(assemblyFileName));
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Load an assembly from the specified location
        /// </summary>
        /// <param name="assemblyLocationInformation">AssemblyLocationInformation</param>
        /// <returns>Assembly</returns>
        public Assembly LoadAssembly(AssemblyLocationInformation assemblyLocationInformation)
        {
            // Check if the simple name can be found in the cache
            if (LoadedAssemblies.TryGetValue(assemblyLocationInformation.Name, out var assembly))
            {
                if (Log.IsInfoEnabled())
                {
                    Log.Info().WriteLine("Returned {0} from cache.", assemblyLocationInformation.Name);
                }
                return(assembly);
            }

            if (assemblyLocationInformation.IsEmbedded)
            {
                return(LoadEmbeddedAssembly(assemblyLocationInformation));
            }
            // Load from file
            return(LoadFromFile(assemblyLocationInformation));
        }
コード例 #5
0
        /// <summary>
        /// This is called when a new assembly is loaded, we need to know this
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="args">AssemblyLoadEventArgs</param>
        private void AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            var loadedAssembly = args.LoadedAssembly;
            var assemblyName   = loadedAssembly.GetName().Name;

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Loaded {0}", assemblyName);
            }
            LoadedAssemblies[assemblyName] = loadedAssembly;

            if (!_applicationConfig.ScanForEmbeddedAssemblies)
            {
                return;
            }

            // Ignore resource checking on certain assemblies
            if (AssembliesToIgnore.IsMatch(assemblyName))
            {
                return;
            }

            string[] resources;
            try
            {
                resources = Resources.GetCachedManifestResourceNames(loadedAssembly);
            }
            catch (Exception ex)
            {
                Log.Warn().WriteLine(ex, "Couldn't retrieve resources from {0}", loadedAssembly.GetName().Name);
                return;
            }
            foreach (var resource in resources)
            {
                var resourceMatch = _assemblyResourceNameRegex.Match(resource);
                if (!resourceMatch.Success)
                {
                    continue;
                }

                var embeddedAssemblyName = resourceMatch.Groups["assembly"].Value;
                if (LoadedAssemblies.ContainsKey(embeddedAssemblyName))
                {
                    // Ignoring already loaded assembly, as we cannot unload.
                    continue;
                }
                var newAssemblyLocation = new AssemblyLocationInformation(embeddedAssemblyName, loadedAssembly, resource);
                if (AvailableAssemblies.TryGetValue(embeddedAssemblyName, out var availableAssemblyLocationInformation))
                {
                    if (availableAssemblyLocationInformation.FileDate > newAssemblyLocation.FileDate)
                    {
                        continue;
                    }
                }
                if (Log.IsVerboseEnabled())
                {
                    Log.Verbose().WriteLine("Detected additional assembly {0} in {1}", embeddedAssemblyName, loadedAssembly.GetName().Name);
                }
                AvailableAssemblies[embeddedAssemblyName] = newAssemblyLocation;
            }
        }
コード例 #6
0
        /// <summary>
        /// Load an assembly via a file, this used via Assembly.Load or Assembly.LoadFrom depending on where the file is or can be stored
        /// </summary>
        /// <param name="additionalInformation">AssemblyLocationInformation used for some decisions</param>
        /// <returns>Assembly</returns>
        private Assembly LoadFromFile(AssemblyLocationInformation additionalInformation)
        {
            // Get the assembly name from the file
            var assemblyName = AssemblyName.GetAssemblyName(additionalInformation.Filename);

            // Check the cache again, this time with the "real" name
            if (LoadedAssemblies.TryGetValue(assemblyName.Name, out var assembly))
            {
                if (Log.IsInfoEnabled())
                {
                    Log.Info().WriteLine("Returned {0} from cache.", assemblyName.Name);
                }
                return(assembly);
            }

            var destination            = $@"{FileLocations.AddonsLocation}\{assemblyName.Name}.dll";
            var destinationIsNotSource = !destination.Equals(additionalInformation.Filename, StringComparison.OrdinalIgnoreCase);

            if (Log.IsDebugEnabled() && !destinationIsNotSource)
            {
                Log.Debug().WriteLine("Skipping copy, as destination and source would be the same.");
            }
            if (_applicationConfig.CopyAssembliesToProbingPath && FileLocations.AddonsLocation != null && destinationIsNotSource)
            {
                try
                {
                    if (ShouldWrite(additionalInformation, destination))
                    {
                        if (Log.IsVerboseEnabled())
                        {
                            Log.Verbose().WriteLine("Creating a copy of {0} to {1}, solving potential context loading issues.", additionalInformation.Filename, destination);
                        }
                        File.Copy(additionalInformation.Filename, destination);
                        // Register delete on exit, this is done by calling a command
                        _assembliesToDeleteAtExit.Add(destination);
                    }
                    // Load via the assembly name, it's not inside the probing path
                    assembly = Assembly.Load(assemblyName);
                    if (assembly != null)
                    {
                        return(assembly);
                    }
                }
                catch (Exception ex)
                {
                    Log.Warn().WriteLine(ex, "Couldn't create a copy of {0} to {1}.", additionalInformation.Filename, destination);
                }
            }

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Loading {0} from {1}.", additionalInformation.Name, additionalInformation.Filename);
            }

            try
            {
                return(Assembly.LoadFrom(additionalInformation.Filename));
            }
            catch (Exception ex)
            {
                Log.Error().WriteLine(ex, "Couldn't load assembly from file {0}", additionalInformation.Filename);
            }
            return(null);
        }