/// <summary>
        /// This will try to resolve the requested assembly by looking into the cache
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="resolveEventArgs">ResolveEventArgs</param>
        /// <returns>Assembly</returns>
        private Assembly AssemblyResolve(object sender, ResolveEventArgs resolveEventArgs)
        {
            var assemblyName = new AssemblyName(resolveEventArgs.Name);

            // Fail fast for resolving .resources requests
            if (assemblyName.Name.EndsWith(".resources"))
            {
                return(null);
            }

            if (Log.IsVerboseEnabled())
            {
                Log.Verbose().WriteLine("Resolving {0}", assemblyName.FullName);
            }
            if (_resolving.Contains(assemblyName.Name))
            {
                Log.Warn().WriteLine("Ignoring recursive resolve event for {0}", assemblyName.Name);
                return(null);
            }

            if (LoadedAssemblies.TryGetValue(assemblyName.Name, out var assemblyResult))
            {
                if (Log.IsVerboseEnabled())
                {
                    Log.Verbose().WriteLine("Returned {0} from cache.", assemblyName.Name);
                }

                return(assemblyResult);
            }

            try
            {
                _resolving.Add(assemblyName.Name);
                if (!AvailableAssemblies.TryGetValue(assemblyName.Name, out var assemblyLocationInformation))
                {
                    return(null);
                }

                if (Log.IsVerboseEnabled())
                {
                    Log.Verbose().WriteLine("Found {0} at {1}.", assemblyName.Name, assemblyLocationInformation.ToString());
                }

                return(LoadAssembly(assemblyLocationInformation));
            }
            finally
            {
                _resolving.Remove(assemblyName.Name);
            }
        }
        /// <summary>
        /// Load a named assembly
        /// </summary>
        /// <param name="assemblyName">string</param>
        /// <returns>Assembly</returns>
        public Assembly LoadAssembly(string assemblyName)
        {
            // Check if the simple name can be found in the cache
            if (LoadedAssemblies.TryGetValue(assemblyName, out var assembly))
            {
                Log.Info().WriteLine("Returned {0} from cache.", assemblyName);
                return(assembly);
            }

            if (AvailableAssemblies.TryGetValue(assemblyName, out var assemblyLocationInformation))
            {
                return(LoadAssembly(assemblyLocationInformation));
            }

            return(Assembly.Load(assemblyName));
        }
        /// <summary>
        /// Internally tries to retrieve a previously compiled template from cache
        /// if not found compiles a template into an assembly
        /// always returns an assembly id as a string.
        /// </summary>
        /// <param name="templateText">The text to parse</param>
        /// <returns>assembly id as a string or null on error</returns>
        protected virtual CompiledAssemblyItem GetAssemblyFromStringAndCache(string templateText)
        {
            var hash = templateText.GetHashCode();

            CompiledAssemblyItem item;

            LoadedAssemblies.TryGetValue(hash, out item);

            string assemblyId = null;

            // Check for cached instance
            if (item != null)
            {
                assemblyId = item.AssemblyId;
            }
            else
            {
                item = new CompiledAssemblyItem();
            }

            // No cached instance - create assembly and cache
            if (assemblyId == null)
            {
                var safeClassName = GetSafeClassName(null);
                using (var reader = new StringReader(templateText))
                {
                    var refAssemblies = ReferencedAssemblies.ToArray();
                    assemblyId = Engine.ParseAndCompileTemplate(refAssemblies, reader, GeneratedNamespace, safeClassName);
                }

                if (assemblyId == null)
                {
                    ErrorMessage = Engine.ErrorMessage;
                    return(null);
                }

                item.AssemblyId     = assemblyId;
                item.CompileTimeUtc = DateTime.UtcNow;
                item.SafeClassName  = safeClassName;

                LoadedAssemblies[hash] = item;
            }

            return(item);
        }
        /// <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));
        }
        /// <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);
        }