/// <summary> /// Unloads a module. /// </summary> /// <param name="moduleData">The module.</param> private static void StopModule(ModuleData moduleData) { try { for (int i = moduleData.Tasks.Length - 1; i >= 0; i--) { TaskManagerService.Logger.Log(string.Format("Stopping task '{0}'...", moduleData.Tasks[i].TaskName)); TaskSupervisor.RemoveTask(moduleData.Tasks[i]); } TaskManagerService.Logger.Log(string.Format("Unloading AppDomain '{0}'...", moduleData.Domain.FriendlyName)); AppDomain.Unload(moduleData.Domain); TaskManagerService.Logger.Log("AppDomain successfully unloaded."); if (moduleData.ZipFile != null && moduleData.ZipDirectory != null) { Directory.Delete(moduleData.ZipDirectory, true); } _moduleList.Remove(moduleData); } catch (Exception e) { TaskManagerService.Logger.Log(string.Format("Exception caught while shutting down module '{0}'", moduleData.DllFile), e); throw; } }
/// <summary> /// Loads a module from a zip file. /// </summary> /// <param name="zipFile">The path to the zip file.</param> /// <param name="startImmediately">True if execution should be started immediately after configuring the module, false if module should be configured but not started.</param> private static void LoadZipAndConfigure(string zipFile, bool startImmediately) { string tempPath = null; int i = 0; while (Directory.Exists(tempPath = Path.Combine(Path.Combine(Path.GetTempPath(), "TaskManager"), Path.GetRandomFileName()))) { i++; if (i == 10) { throw new Exception("Failed to create a new temporary folder."); } } if (!tempPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { tempPath += Path.DirectorySeparatorChar; } string overridePath = Path.Combine(Path.GetDirectoryName(zipFile), Path.GetFileNameWithoutExtension(zipFile)) + Path.DirectorySeparatorChar; string loaderDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll"); string tempLoaderDll = Path.Combine(tempPath, "TaskManager.Loader.dll"); string commonDll = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Common.dll"); string tempCommonDll = Path.Combine(tempPath, "TaskManager.Common.dll"); List <string> dependencies = new List <string>(); DirectoryInfo directoryInfo = Directory.CreateDirectory(tempPath); try { using (Stream fileStream = File.Open(zipFile, FileMode.Open, FileAccess.Read)) { using (ZipArchive zip = new ZipArchive(fileStream, ZipArchiveMode.Read)) { var directory = zip.Entries; foreach (var compressedFile in directory) { string destinationFile = Path.Combine(tempPath, compressedFile.FullName); string overrideFile = Path.Combine(overridePath, compressedFile.FullName); dependencies.Add(overrideFile); compressedFile.ExtractToFile(destinationFile, true); } } } if (Directory.Exists(overridePath)) { foreach (string overrideFile in Directory.GetFiles(overridePath, "*.*", SearchOption.AllDirectories)) { if (!dependencies.Contains(overrideFile)) { dependencies.Add(overrideFile); } dependencies.Add(Path.Combine(overridePath, overrideFile.Replace(tempPath, string.Empty))); string relativeName = overrideFile.Replace(overridePath, string.Empty); string destination = Path.Combine(tempPath, relativeName); string destinationPath = Path.GetDirectoryName(destination); if (!Directory.Exists(destinationPath)) { Directory.CreateDirectory(destinationPath); } File.Copy(overrideFile, destination, true); } } List <string> possibleFiles = new List <string>(); foreach (string moduleFile in Directory.GetFiles(tempPath, "*" + ModuleFileDefaultExtension, SearchOption.AllDirectories)) { string xmlFile = Path.ChangeExtension(moduleFile, ConfigFileDefaultExtension); if (File.Exists(xmlFile)) { possibleFiles.Add(moduleFile); } } File.Copy(loaderDll, tempLoaderDll, true); File.Copy(commonDll, tempCommonDll, true); foreach (string dllFile in possibleFiles) { string xmlFile = Path.ChangeExtension(dllFile, ConfigFileDefaultExtension); if (File.Exists(xmlFile)) { if (!xmlFile.IsValidConfigurationFile()) { continue; } string modulePath = Path.GetDirectoryName(dllFile); string[] files = Directory.GetFiles(modulePath, "*.*", SearchOption.AllDirectories); AppDomainSetup domainSetup = new AppDomainSetup(); domainSetup.ShadowCopyFiles = "true"; domainSetup.ApplicationBase = tempPath; domainSetup.ConfigurationFile = dllFile + ".config"; AppDomain domain = AppDomain.CreateDomain(dllFile, null, domainSetup); TaskWrapper[] tasks = new TaskWrapper[0]; try { TaskManagerService.Logger.Log(string.Format("Module found: '{0}', configuration file: '{1}', scanning assembly for tasks...", dllFile, xmlFile)); AssemblyName loaderAssemblyName = AssemblyName.GetAssemblyName(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TaskManager.Loader.dll")); Loader loader = (Loader)domain.CreateInstanceAndUnwrap(loaderAssemblyName.ToString(), "TaskManager.Loader"); tasks = loader.LoadAndConfigure(dllFile, xmlFile, TaskManagerService.Logger, AppDomain.CurrentDomain.BaseDirectory); ModuleData newModule = new ModuleData(); newModule.BasePath = overridePath; newModule.Tasks = tasks; newModule.DllFile = dllFile; newModule.XmlFile = xmlFile; newModule.ZipFile = zipFile; newModule.ZipDirectory = tempPath; newModule.Files = new List <string>(files); newModule.Files.AddRange(dependencies); newModule.Files.Add(zipFile); newModule.Domain = domain; if (startImmediately) { foreach (TaskWrapper task in newModule.Tasks) { TaskSupervisor.ScheduleTask(task); } } _moduleList.Add(newModule); } catch (Exception ex) { foreach (TaskWrapper task in tasks) { try { TaskSupervisor.RemoveTask(task); } catch { } } AppDomain.Unload(domain); TaskManagerService.Logger.Log(string.Format("Unable to load module '{0}' from zipped file '{1}'.", dllFile, zipFile), ex); } } } foreach (ModuleData module in _moduleList) { if (module.ZipFile == zipFile) { return; } } throw new Exception(string.Format("Unable to find tasks in zipped file '{0}'.", zipFile)); } catch { try { Directory.Delete(tempPath, true); } catch (Exception ex) { TaskManagerService.Logger.Log(string.Format("Unable to remove temporary directory '{0}'.", tempPath), ex); } throw; } }