/// <summary> /// Initialize /// </summary> public static void Initialize() { var isFullTrust = WebHelper.GetTrustLevel() == AspNetHostingPermissionLevel.Unrestricted; if (!isFullTrust) { throw new ApplicationException("SmartStore.NET requires Full Trust mode. Please enable Full Trust for your web site or contact your hosting provider."); } using (var updater = new AppUpdater()) { // update from NuGet package, if it exists and is valid if (updater.TryUpdateFromPackage()) { // [...] } // execute migrations updater.ExecuteMigrations(); } // adding a process-specific environment path (either bin/x86 or bin/x64) // ensures that unmanaged native dependencies can be resolved successfully. SetNativeDllPath(); //SetPrivateEnvPath(); DynamicModuleUtility.RegisterModule(typeof(AutofacRequestLifetimeHttpModule)); #region Plugins var incompatiblePlugins = new HashSet <string>(StringComparer.OrdinalIgnoreCase); using (Locker.GetWriteLock()) { _shadowCopyDir = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory); var plugins = LoadPluginDescriptors().ToArray(); var compatiblePlugins = plugins.Where(x => !x.Incompatible).ToArray(); // If plugins state is dirty, we copy files over to the dynamic folder, // otherwise we just reference the previously copied file. var dirty = DetectAndCleanStalePlugins(compatiblePlugins); foreach (var plugin in plugins) { if (plugin.Incompatible) { incompatiblePlugins.Add(plugin.SystemName); continue; } else { _referencedPlugins[plugin.SystemName] = plugin; } try { // Shadow copy main plugin assembly plugin.ReferencedAssembly = Probe(plugin.OriginalAssemblyFile, dirty); // Shadow copy other referenced plugin local assemblies if (plugin.ReferencedLocalAssemblyFiles != null) { foreach (var assemblyFile in plugin.ReferencedLocalAssemblyFiles) { Probe(assemblyFile, dirty); } } if (!plugin.Installed) { _inactiveAssemblies.Add(plugin.ReferencedAssembly); } // Initialize: Find IPlugin, IPreApplicationStart, IConfigurable etc. ActivatePlugin(plugin); } catch (UnauthorizedAccessException) { // Throw the exception if its UnauthorizedAccessException as this will // be because we most likely cannot copy to the dynamic folder. throw; } catch (ReflectionTypeLoadException ex) { var msg = string.Empty; foreach (var e in ex.LoaderExceptions) { msg += e.Message + Environment.NewLine; } HandlePluginActivationException(ex, plugin, msg, incompatiblePlugins); } catch (Exception ex) { var msg = string.Empty; for (var e = ex; e != null; e = e.InnerException) { msg += e.Message + Environment.NewLine; } HandlePluginActivationException(ex, plugin, msg, incompatiblePlugins); } } if (dirty) { // Save current hash of all deployed plugins to disk var hash = ComputePluginsHash(_referencedPlugins.Values.OrderBy(x => x.FolderName).ToArray()); SavePluginsHash(hash); // Save names of all deployed assemblies to disk (so we can nuke them later) SavePluginsAssemblies(_referencedPlugins.Values); } IncompatiblePlugins = incompatiblePlugins.AsReadOnly(); } #endregion }
private static void InitializeCore() { var isFullTrust = WebHelper.GetTrustLevel() == AspNetHostingPermissionLevel.Unrestricted; if (!isFullTrust) { throw new ApplicationException("Smartstore requires Full Trust mode. Please enable Full Trust for your web site or contact your hosting provider."); } using (var updater = new AppUpdater()) { // update from NuGet package, if it exists and is valid if (updater.TryUpdateFromPackage()) { // [...] } // execute migrations updater.ExecuteMigrations(); } // adding a process-specific environment path (either bin/x86 or bin/x64) // ensures that unmanaged native dependencies can be resolved successfully. SetNativeDllPath(); DynamicModuleUtility.RegisterModule(typeof(AutofacRequestLifetimeHttpModule)); var incompatiblePlugins = (new HashSet <string>(StringComparer.OrdinalIgnoreCase)).AsSynchronized(); var inactiveAssemblies = _inactiveAssemblies.AsSynchronized(); var dirty = false; var watch = Stopwatch.StartNew(); _shadowCopyDir = new DirectoryInfo(AppDomain.CurrentDomain.DynamicDirectory); var plugins = LoadPluginDescriptors().ToArray(); var compatiblePlugins = plugins.Where(x => !x.Incompatible).ToArray(); var hasher = new PluginsHasher(compatiblePlugins); Logger.DebugFormat("Loaded plugin descriptors. {0} total, {1} incompatible.", plugins.Length, plugins.Length - compatiblePlugins.Length); var ms = watch.ElapsedMilliseconds; Logger.DebugFormat("INIT PLUGINS (LoadPluginDescriptors). Time elapsed: {0} ms.", ms); // If plugins state is dirty, we copy files over to the dynamic folder, // otherwise we just reference the previously copied file. dirty = DetectAndCleanStalePlugins(compatiblePlugins, hasher); // Perf: Initialize/probe all plugins in parallel plugins.AsParallel().ForAll(x => { // Deploy to ASP.NET dynamic folder. DeployPlugin(x, dirty); // Finalize FinalizePlugin(x); }); //// Retry when failed, because during parallel execution assembly loading MAY fail. //// Therefore we retry initialization for failed plugins, but sequentially this time. //foreach (var p in plugins) //{ // // INFO: this seems redundant, but it's ok: // // DeployPlugin() only probes assemblies that are not loaded yet. // DeployPlugin(p, dirty); // // Finalize // FinalizePlugin(p); //} if (dirty && DataSettings.DatabaseIsInstalled()) { // Save current hash of all deployed plugins to disk hasher.Persist(); // Save names of all deployed assemblies to disk (so we can nuke them later) SavePluginsAssemblies(_referencedPlugins.Values); } IncompatiblePlugins = incompatiblePlugins.AsReadOnly(); ms = watch.ElapsedMilliseconds; Logger.DebugFormat("INIT PLUGINS (Deployment complete). Time elapsed: {0} ms.", ms); void DeployPlugin(PluginDescriptor p, bool shadowCopy) { if (p.Incompatible) { // Do nothing if plugin is incompatible return; } // First copy referenced local assemblies (if any) for (int i = 0; i < p.ReferencedLocalAssemblies.Length; ++i) { var refAr = p.ReferencedLocalAssemblies[i]; if (refAr.Assembly == null) { Probe(refAr, p, shadowCopy); } } // Then copy main plugin assembly var ar = p.Assembly; if (ar.Assembly == null) { Probe(ar, p, shadowCopy); if (ar.Assembly != null) { // Activate (even if uninstalled): Find IPlugin, IPreApplicationStart, IConfigurable etc. ActivatePlugin(p); } } } void FinalizePlugin(PluginDescriptor p) { _referencedPlugins[p.SystemName] = p; if (p.Incompatible) { incompatiblePlugins.Add(p.SystemName); return; } var firstFailedAssembly = p.ReferencedLocalAssemblies.FirstOrDefault(x => x.ActivationException != null); if (firstFailedAssembly == null && p.Assembly.ActivationException != null) { firstFailedAssembly = p.Assembly; } if (firstFailedAssembly != null) { Logger.ErrorFormat("Assembly probing failed for '{0}': {1}", firstFailedAssembly.File.Name, firstFailedAssembly.ActivationException.Message); p.Incompatible = true; incompatiblePlugins.Add(p.SystemName); } if ((!p.Installed || firstFailedAssembly != null) && p.Assembly.Assembly != null) { inactiveAssemblies.Add(p.Assembly.Assembly); } } }
/// <summary> /// Initialize /// </summary> public static void Initialize() { using (var updater = new AppUpdater()) { // update from NuGet package, if it exists and is valid if (updater.TryUpdateFromPackage()) { // [...] } // execute migrations updater.ExecuteMigrations(); } // adding a process-specific environment path (either bin/x86 or bin/amd64) // ensures that unmanaged native dependencies can be resolved successfully. SetPrivateEnvPath(); DynamicModuleUtility.RegisterModule(typeof(AutofacRequestLifetimeHttpModule)); using (Locker.GetWriteLock()) { // TODO: Add verbose exception handling / raising here since this is happening on app startup and could // prevent app from starting altogether var pluginFolderPath = CommonHelper.MapPath(_pluginsPath); _shadowCopyFolder = new DirectoryInfo(CommonHelper.MapPath(_shadowCopyPath)); var incompatiblePlugins = new List <string>(); _clearShadowDirectoryOnStartup = CommonHelper.GetAppSetting <bool>("sm:ClearPluginsShadowDirectoryOnStartup", true); try { Debug.WriteLine("Creating shadow copy folder and querying for dlls"); //ensure folders are created Directory.CreateDirectory(pluginFolderPath); Directory.CreateDirectory(_shadowCopyFolder.FullName); // get list of all files in bin var binFiles = _shadowCopyFolder.GetFiles("*", SearchOption.AllDirectories); if (_clearShadowDirectoryOnStartup) { // clear out shadow copied plugins foreach (var f in binFiles) { Debug.WriteLine("Deleting " + f.Name); try { File.Delete(f.FullName); } catch (Exception exc) { Debug.WriteLine("Error deleting file " + f.Name + ". Exception: " + exc); } } } // determine all plugin folders var pluginPaths = from x in Directory.EnumerateDirectories(pluginFolderPath) where !x.IsMatch("bin") && !x.IsMatch("_Backup") select Path.Combine(pluginFolderPath, x); var installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(); // now activate all plugins foreach (var pluginPath in pluginPaths) { var result = LoadPluginFromFolder(pluginPath, installedPluginSystemNames); if (result != null) { if (result.IsIncompatible) { incompatiblePlugins.Add(result.Descriptor.SystemName); } else if (result.Success) { _referencedPlugins[result.Descriptor.SystemName] = result.Descriptor; } } } } catch (Exception ex) { var msg = string.Empty; for (var e = ex; e != null; e = e.InnerException) { msg += e.Message + Environment.NewLine; } var fail = new Exception(msg, ex); Debug.WriteLine(fail.Message, fail); throw fail; } IncompatiblePlugins = incompatiblePlugins.AsReadOnly(); } }