/// <summary> /// Report the changes for a folder /// </summary> /// <param name="folder">Folder to run the report for</param> /// <param name="handlers">List of SyncHandlers to use for the report</param> /// <param name="callbacks">Callback functions to keep UI uptodate</param> /// <returns>List of actions detailing what would and wouldn't change</returns> public IEnumerable <uSyncAction> Report(string folder, IEnumerable <ExtendedHandlerConfigPair> handlers, uSyncCallbacks callbacks) { var sw = Stopwatch.StartNew(); fireBulkStarting(ReportStarting); logger.Debug <uSyncService>("Reporting For [{0}]", string.Join(",", handlers.Select(x => x.Handler.Name))); var actions = new List <uSyncAction>(); var summary = new SyncProgressSummary(handlers.Select(x => x.Handler), "Reporting", handlers.Count()); if (GlobalSettings.DebugMode && settings.ReportDebug) { // debug - full export into a dated folder. summary.UpdateMessage("Debug: Creating Extract in Tracker folder"); logger.Warn <uSyncService>("Running Report Debug - this can be a slow process, don't enable unless you need it"); callbacks?.Callback?.Invoke(summary); this.Export($"~/uSync/Tracker/{DateTime.Now.ToString("yyyyMMdd_HHmmss")}/", handlers, callbacks); } foreach (var configuredHandler in handlers) { var handler = configuredHandler.Handler; var handlerSettings = configuredHandler.Settings; summary.Increment(); summary.UpdateHandler(handler.Name, HandlerStatus.Processing, $"Reporting {handler.Name}", 0); callbacks?.Callback?.Invoke(summary); var handlerActions = handler.Report($"{folder}/{handler.DefaultFolder}", handlerSettings, callbacks?.Update); actions.AddRange(handlerActions); summary.UpdateHandler(handler.Name, HandlerStatus.Complete, handlerActions.CountChanges(), handlerActions.ContainsErrors()); } summary.UpdateMessage("Report Complete"); callbacks?.Callback?.Invoke(summary); fireBulkComplete(ReportComplete, actions); sw.Stop(); logger.Info <uSyncService>("uSync Report: {handlerCount} handlers, processed {itemCount} items, {changeCount} changes in {ElapsedMilliseconds}ms", handlers.Count(), actions.Count, actions.CountChanges(), sw.ElapsedMilliseconds); callbacks?.Update?.Invoke($"Processed {actions.Count} items in {sw.ElapsedMilliseconds}ms", 1, 1); return(actions); }
public IEnumerable <ExtendedHandlerConfigPair> GetValidHandlers(SyncHandlerOptions options = null) { if (options == null) { options = new SyncHandlerOptions(this.DefaultSet); } EnsureHandlerSet(options); var set = config.Settings.HandlerSets .Where(x => x.Name.InvariantEquals(options.Set)) .FirstOrDefault(); if (set == null || set.Handlers.Count == 0) { logger.Warn <SyncHandlerFactory>("No Handlers configured for requested set {setName}", options.Set); return(Enumerable.Empty <ExtendedHandlerConfigPair>()); } var configs = new List <ExtendedHandlerConfigPair>(); foreach (var settings in set.Handlers.Where(x => x.Enabled)) { // Get the handler var handler = syncHandlers.ExtendedHandlers .Where(x => x.Alias.InvariantEquals(settings.Alias)) .FirstOrDefault(); // check its valid for the passed group and action. if (handler != null && IsValidGroup(options.Group, handler) && IsValidAction(options.Action, settings.Actions)) { // logger.Debug<SyncHandlerFactory>("Adding {handler} to ValidHandler List", handler.Alias); configs.Add(new ExtendedHandlerConfigPair() { Handler = handler, Settings = settings }); } else { // only log if we are doing the default 'everything' group // because weh nfoing groups we choose not to load things. if (string.IsNullOrWhiteSpace(options.Group)) { logger.Warn <SyncHandlerFactory>("No Handler with {alias} has been loaded", settings.Alias); } } } return(configs.OrderBy(x => x.Handler.Priority)); }
private void RebuildDatabaseCacheIfSerializerChanged() { var serializer = ConfigurationManager.AppSettings[Nucache_Serializer_Key]; var currentSerializer = _keyValueService.GetValue(Nucache_Serializer_Key); if (currentSerializer == null) { currentSerializer = JSON_SERIALIZER_VALUE; } if (serializer == null) { serializer = JSON_SERIALIZER_VALUE; } if (serializer != currentSerializer) { _profilingLogger.Warn <NuCacheSerializerComponent>($"Database NuCache was serialized using {currentSerializer}. Currently configured NuCache serializer {serializer}. Rebuilding Nucache"); using (_profilingLogger.TraceDuration <NuCacheSerializerComponent>($"Rebuilding NuCache database with {currentSerializer} serializer")) { _service.Value.Rebuild(); _keyValueService.SetValue(Nucache_Serializer_Key, serializer); } } }
/// <summary> /// add the given section to the given user group /// </summary> /// <remarks> /// if umbraco throws an exception here, we capture it /// because if we don't umbraco won't startup and that /// might be a bad thing :( /// </remarks> /// <param name="groupAlias"></param> /// <param name="sectionAlias"></param> private void AddSection(string groupAlias, string sectionAlias) { using (logger.DebugDuration <CustomSectionComponent>($"Adding Section {sectionAlias} to {groupAlias}")) { var group = userService.GetUserGroupByAlias(groupAlias); if (group != null) { if (!group.AllowedSections.Contains(sectionAlias)) { group.AddAllowedSection(sectionAlias); try { userService.Save(group); logger.Info <CustomSectionComponent>($"Section {sectionAlias} added to {groupAlias} group"); } catch (Exception ex) { logger.Warn <CustomSectionComponent>("Error adding section {0} to group {1} [{2}]", sectionAlias, groupAlias, ex.Message); } } } } }
virtual public void ImportSecondPass(string file, TObject item, HandlerSettings config, SyncUpdateCallback callback) { if (IsTwoPass) { try { syncFileService.EnsureFileExists(file); var flags = SerializerFlags.None; if (config.BatchSave) { flags |= SerializerFlags.DoNotSave; } using (var stream = syncFileService.OpenRead(file)) { var node = XElement.Load(stream); serializer.DeserializeSecondPass(item, node, flags); stream.Dispose(); } } catch (Exception ex) { logger.Warn <TObject>($"Second Import Failed: {ex.Message}"); } } }
public void Initialize() { // double check - is this on in config // are we in upgrade mode (we should be - we only register in upgrade) if (!SilentUpgradeOn || runtimeState.Level != RuntimeLevel.Upgrade) { return; } // Do we need to lock? the upgrade so it only happens once? logger.Debug <SilentUpgradeComponent>("Silently upgrading the Site"); // The 'current' steps for upgrading Umbraco try { // // If these steps change in the core then this will be wrong. // // We don't run the file permission step, we assume you have that sorted already. // and besides its internal and we can't get to the tests // FilePermissionHelper.RunFilePermissionTestSuite(out result); // Step: 'DatabaseInstallStep' var result = databaseBuilder.CreateSchemaAndData(); if (!result.Success) { // failed. throw new Exception("Upgrade Failed - Create Schema"); } // Step: 'DatabaseUpgradeStep' var plan = new UmbracoPlan(); logger.Debug <SilentUpgradeComponent>("Running Migrations {initialState} to {finalState}", plan.InitialState, plan.FinalState); var upgrade = databaseBuilder.UpgradeSchemaAndData(plan); if (!upgrade.Success) { throw new Exception("Upgrade Failed - Upgrade Schema"); } // Step: 'SetUmbracoVersionStep' // Update the version number inside the web.config logger.Debug <SilentUpgradeComponent>("Updating version in the web.config {version}", UmbracoVersion.SemanticVersion.ToSemanticString()); // Doing this essentially restats the site. globalSettings.ConfigurationStatus = UmbracoVersion.SemanticVersion.ToSemanticString(); // put something in the log. logger.Info <SilentUpgradeComponent>("Silent Upgrade Completed {version}", UmbracoVersion.SemanticVersion.ToSemanticString()); Upgraded = true; } catch (Exception ex) { logger.Warn <SilentUpgradeComponent>(ex, "Silent Upgrade Failed"); Upgraded = false; // if this is false, we should fall through to the 'standard' upgrade path. } }
private void InitBackOffice() { var sw = Stopwatch.StartNew(); try { using (var reference = umbracoContextFactory.EnsureUmbracoContext()) { if (uSyncSettings.ExportAtStartup || (uSyncSettings.ExportOnSave && !syncFileService.RootExists(uSyncSettings.RootFolder))) { logger.Info <uSyncBackofficeComponent>("uSync: Running Export at startup"); uSyncService.Export(uSyncSettings.RootFolder, default(SyncHandlerOptions)); } if (uSyncSettings.ImportAtStartup) { logger.Info <uSyncBackofficeComponent>("uSync: Running Import at startup"); if (!HasStopFile(uSyncSettings.RootFolder)) { uSyncService.Import(uSyncSettings.RootFolder, false, new SyncHandlerOptions { Group = uSyncSettings.ImportAtStartupGroup }); ProcessOnceFile(uSyncSettings.RootFolder); } else { logger.Info <uSyncBackofficeComponent>("Startup Import blocked by usync.stop file"); } } if (uSyncSettings.ExportOnSave) { var handlers = handlerFactory .GetValidHandlers(new SyncHandlerOptions(handlerFactory.DefaultSet, HandlerActions.Save)) .ToList(); logger.Info <uSyncBackofficeComponent>("uSync: Initializing events for {count} Handlers", handlers.Count); foreach (var syncHandler in handlers) { logger.Debug <uSyncBackofficeComponent>($" Initializing up Handler {syncHandler.Handler.Name}"); syncHandler.Handler.Initialize(syncHandler.Settings); } } } sw.Stop(); logger.Info <uSyncBackofficeComponent>("uSync: Startup Processes Complete {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds); } catch (Exception ex) { logger.Warn <uSyncBackofficeComponent>($"uSync: Error during at startup {ex.Message}"); } }
/// <summary> /// Load the usync settings from disk. /// </summary> public uSyncSettings LoadSettings() { uSyncSettings settings = new uSyncSettings(); var node = GetSettingsFile(); if (node == null) { logger.Warn <uSyncConfig>($"Failed to load the {uSyncBackOfficeConstants.ConfigFile} file from disk, working with defaults."); return(SaveSettings(settings)); } settings.RootFolder = ValueFromWebConfigOrDefault("Folder", node.Element("Folder").ValueOrDefault(settings.RootFolder)); settings.UseFlatStructure = ValueFromWebConfigOrDefault("FlatFolders", node.Element("FlatFolders").ValueOrDefault(true)); settings.ImportAtStartup = ValueFromWebConfigOrDefault("ImportAtStartup", node.Element("ImportAtStartup").ValueOrDefault(true)); settings.ExportAtStartup = ValueFromWebConfigOrDefault("ExportAtStartup", node.Element("ExportAtStartup").ValueOrDefault(false)); settings.ExportOnSave = ValueFromWebConfigOrDefault("ExportOnSave", node.Element("ExportOnSave").ValueOrDefault(true)); settings.UseGuidNames = ValueFromWebConfigOrDefault("UseGuidFilenames", node.Element("UseGuidFilenames").ValueOrDefault(false)); settings.ReportDebug = node.Element("ReportDebug").ValueOrDefault(false); settings.AddOnPing = node.Element("AddOnPing").ValueOrDefault(true); settings.RebuildCacheOnCompletion = node.Element("RebuildCacheOnCompletion").ValueOrDefault(false); settings.FailOnMissingParent = node.Element("FailOnMissingParent").ValueOrDefault(true); settings.CacheFolderKeys = node.Element("CacheFolderKeys").ValueOrDefault(true); // load the handlers var handlerSets = node.Element("HandlerSets"); if (handlerSets != null) { settings.HandlerSets = LoadHandlerSets(handlerSets, settings, out string defaultSet); settings.DefaultSet = defaultSet; } else { var handlers = node.Element("Handlers"); if (handlers != null) { // old config, load as default :( settings.HandlerSets = new List <HandlerSet>(); var defaultSet = LoadSingleHandlerSet(handlers, settings); settings.HandlerSets.Add(defaultSet); } } settings.CustomMappings = LoadAppKeysFromNode(node, "Mappings", true); // fire the loaded event, so things can tell when they are loaded. Reloaded?.Invoke(settings); return(settings); }
/// <summary> /// Executes a macro of a given type. /// </summary> private Attempt <MacroContent> ExecuteProfileMacroWithErrorWrapper(MacroModel macro, string msgIn, Func <MacroContent> getMacroContent, Func <string> msgErr) { try { return(Attempt.Succeed(getMacroContent())); } catch (Exception e) { Exceptions.Add(e); _plogger.Warn <MacroRenderer>(e, "Failed {MsgIn}", msgIn); var macroErrorEventArgs = new MacroErrorEventArgs { Name = macro.Name, Alias = macro.Alias, MacroSource = macro.MacroSource, Exception = e, Behaviour = Current.Configs.Settings().Content.MacroErrorBehaviour }; OnError(macroErrorEventArgs); switch (macroErrorEventArgs.Behaviour) { case MacroErrorBehaviour.Inline: // do not throw, eat the exception, display the trace error message return(Attempt.Fail(new MacroContent { Text = msgErr() }, e)); case MacroErrorBehaviour.Silent: // do not throw, eat the exception, do not display anything return(Attempt.Fail(new MacroContent { Text = string.Empty }, e)); case MacroErrorBehaviour.Content: // do not throw, eat the exception, display the custom content return(Attempt.Fail(new MacroContent { Text = macroErrorEventArgs.Html ?? string.Empty }, e)); //case MacroErrorBehaviour.Throw: default: // see http://issues.umbraco.org/issue/U4-497 at the end // throw the original exception throw; } } }
private bool IsGitHubUsernameValid(string githubUser) { try { var userUrl = new Uri($"https://api.github.com/users/{githubUser}"); var contentsJson = _httpClient.GetStringAsync(userUrl).Result; return(true); } catch (Exception ex) { _logger.Warn <GuestbookGitHubService>("Invalid Github username {Name}", githubUser); return(false); } }
public override async Task <bool> PerformRunAsync(CancellationToken token) { // not on replicas nor unknown role servers switch (_runtime.ServerRole) { case ServerRole.Replica: _logger.Debug <KeepAlive>("Does not run on replica servers."); return(true); // role may change! case ServerRole.Unknown: _logger.Debug <KeepAlive>("Does not run on servers with unknown role."); return(true); // role may change! } // ensure we do not run if not main domain, but do NOT lock it if (_runtime.IsMainDom == false) { _logger.Debug <KeepAlive>("Does not run if not MainDom."); return(false); // do NOT repeat, going down } using (_logger.DebugDuration <KeepAlive>("Keep alive executing", "Keep alive complete")) { var keepAlivePingUrl = _keepAliveSection.KeepAlivePingUrl; try { if (keepAlivePingUrl.Contains("{umbracoApplicationUrl}")) { var umbracoAppUrl = _runtime.ApplicationUrl.ToString(); if (umbracoAppUrl.IsNullOrWhiteSpace()) { _logger.Warn <KeepAlive>("No umbracoApplicationUrl for service (yet), skip."); return(true); // repeat } keepAlivePingUrl = keepAlivePingUrl.Replace("{umbracoApplicationUrl}", umbracoAppUrl.TrimEnd(Constants.CharArrays.ForwardSlash)); } var request = new HttpRequestMessage(HttpMethod.Get, keepAlivePingUrl); var result = await _httpClient.SendAsync(request, token); } catch (Exception ex) { _logger.Error <KeepAlive>(ex, "Keep alive failed (at '{keepAlivePingUrl}').", keepAlivePingUrl); } } return(true); // repeat }
/// <summary> /// load a file into a XElement object. /// </summary> public XElement LoadXElement(string file) { EnsureFileExists(file); try { using (var stream = OpenRead(file)) { return(XElement.Load(stream)); } } catch (Exception ex) { logger.Warn <SyncFileService>("Error while reading in {file} {message}", file, ex.Message); throw new Exception($"Error while reading in {file}", ex); } }
public async override Task <bool> PerformRunAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { _logger.Warn(GetType(), "Background task cancellation requested in {Type:l}.", GetType()); return(false); } _logger.Info <OnlySportCsvExportTask>(nameof(OnlySportCsvExportTask) + " running"); var matches = (await _matchDataSource.ReadMatchListings(new MatchFilter { FromDate = DateTimeOffset.UtcNow }, MatchSortOrder.MatchDateEarliestFirst).ConfigureAwait(false)).Select(x => new OnlySportCsvRecord { MatchId = x.MatchId.GetHashCode() > 0 ? x.MatchId.GetHashCode() : x.MatchId.GetHashCode() * -1, Title = x.MatchName, StartTime = x.StartTime.ToUnixTimeSeconds(), Latitude = x.MatchLocation?.Latitude, Longitude = x.MatchLocation?.Longitude, Website = "https://www.stoolball.org.uk" + x.MatchRoute, Description = x.Description() }).ToList(); var path = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, @"App_Data\csv"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } using (var writer = new StreamWriter(Path.Combine(path, "onlysport.csv"))) { using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecords(matches); } } // Keep repeating return(true); }
public bool SaveHtml(Guid packId, int itemId) { try { var item = contentService.GetById(itemId); if (item != null && item.Published) { var html = GenerateItemHtml(itemId); var path = GetItemPath(itemId); var filePath = $"{syncRoot}/{packId}/{path}/index.html".Replace("/", "\\"); syncFileService.SaveFile(filePath, html); return(true); } } catch (Exception ex) { logger.Warn <uSyncStaticSiteService>("Error Saving Html", ex); } return(false); }
// ensure that the factory is running with the lastest generation of models internal Infos EnsureModels() { if (_debugLevel > 0) { _logger.Debug <PureLiveModelFactory>("Ensuring models."); } // don't use an upgradeable lock here because only 1 thread at a time could enter it try { _locker.EnterReadLock(); if (_hasModels) { return(_infos); } } finally { if (_locker.IsReadLockHeld) { _locker.ExitReadLock(); } } var buildManagerLocked = false; try { // always take the BuildManager lock *before* taking the _locker lock // to avoid possible deadlock situations (see notes above) Monitor.Enter(TheBuildManager, ref buildManagerLocked); _locker.EnterUpgradeableReadLock(); if (_hasModels) { return(_infos); } _locker.EnterWriteLock(); // we don't have models, // either they haven't been loaded from the cache yet // or they have been reseted and are pending a rebuild using (_logger.DebugDuration <PureLiveModelFactory>("Get models.", "Got models.")) { try { var assembly = GetModelsAssembly(_pendingRebuild); // the one below can be used to simulate an issue with BuildManager, ie it will register // the models with the factory but NOT with the BuildManager, which will not recompile views. // this is for U4-8043 which is an obvious issue but I cannot replicate //_modelsAssembly = _modelsAssembly ?? assembly; // the one below is the normal one _modelsAssembly = assembly; var types = assembly.ExportedTypes.Where(x => x.Inherits <PublishedContentModel>() || x.Inherits <PublishedElementModel>()); _infos = RegisterModels(types); _errors.Clear(); } catch (Exception e) { try { _logger.Error <PureLiveModelFactory>(e, "Failed to build models."); _logger.Warn <PureLiveModelFactory>("Running without models."); // be explicit _errors.Report("Failed to build PureLive models.", e); } finally { _modelsAssembly = null; _infos = new Infos { ModelInfos = null, ModelTypeMap = new Dictionary <string, Type>() }; } } // don't even try again _hasModels = true; } return(_infos); } finally { if (_locker.IsWriteLockHeld) { _locker.ExitWriteLock(); } if (_locker.IsUpgradeableReadLockHeld) { _locker.ExitUpgradeableReadLock(); } if (buildManagerLocked) { Monitor.Exit(TheBuildManager); } } }
public async override Task <bool> PerformRunAsync(CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { _logger.Warn(GetType(), "Background task cancellation requested in {Type:l}.", GetType()); return(false); } _logger.Info <SpogoCsvExportTask>(nameof(SpogoCsvExportTask) + " running"); var teams = (await _teamDataSource.ReadTeams(new TeamFilter { ActiveTeams = true, TeamTypes = new List <TeamType?> { TeamType.Regular } }).ConfigureAwait(false)).Select(x => new SpogoCsvRecord { TeamId = x.TeamId.Value.GetHashCode() > 0 ? x.TeamId.Value.GetHashCode() : x.TeamId.Value.GetHashCode() * -1, TeamName = x.TeamName + " Stoolball Club", Description = FormatTeamDescription(x), PlayerType = x.PlayerType.Humanize(), HomeGroundName = x.MatchLocations.FirstOrDefault()?.Name(), StreetName = x.MatchLocations.FirstOrDefault()?.StreetDescription, Locality = x.MatchLocations.FirstOrDefault()?.Locality, Town = x.MatchLocations.FirstOrDefault()?.Town, AdministrativeArea = x.MatchLocations.FirstOrDefault()?.AdministrativeArea, Postcode = x.MatchLocations.FirstOrDefault()?.Postcode, Country = "England", Latitude = x.MatchLocations.FirstOrDefault()?.Latitude, Longitude = x.MatchLocations.FirstOrDefault()?.Longitude, Website = !string.IsNullOrWhiteSpace(x.Website) ? x.Website : "https://www.stoolball.org.uk" + x.TeamRoute, ContactEmail = _contactDetailsParser.ParseFirstEmailAddress(x.PublicContactDetails), ContactPhone = _contactDetailsParser.ParseFirstPhoneNumber(x.PublicContactDetails) }).Where(x => !string.IsNullOrEmpty(x.ContactEmail) || !string.IsNullOrEmpty(x.ContactPhone)).ToList(); var path = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, @"App_Data\csv"); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } using (var writer = new StreamWriter(Path.Combine(path, "spogo-protected.csv"))) { using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecords(teams); } } foreach (var team in teams) { team.ContactEmail = team.ContactPhone = string.Empty; } using (var writer = new StreamWriter(Path.Combine(path, "spogo.csv"))) { using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) { csv.WriteRecords(teams); } } // Keep repeating return(true); }
/// <summary> /// Load the usync settings from disk. /// </summary> public uSyncSettings LoadSettings() { uSyncSettings settings = new uSyncSettings(); var node = GetSettingsFile(); if (node == null) { logger.Warn <uSyncConfig>($"Failed to load the {uSyncBackOfficeConstants.ConfigFile} file from disk, working with defaults."); return(SaveSettings(settings)); } settings.SettingsFolder = ValueFromWebConfigOrDefault("Folder", node.Element("Folder").ValueOrDefault(settings.RootFolder)); var allowUnsafeFolder = ValueFromWebConfigOrDefault("AllowUnsafeFolder", node.Element("Folder").Attribute("AllowUnsafe").ValueOrDefault(false)); settings.RootFolder = GetPhysicalFolder(settings.SettingsFolder, allowUnsafeFolder); settings.UseFlatStructure = ValueFromWebConfigOrDefault("FlatFolders", node.Element("FlatFolders").ValueOrDefault(true)); settings.ImportAtStartup = ValueFromWebConfigOrDefault("ImportAtStartup", node.Element("ImportAtStartup").ValueOrDefault(true)); // new add a group to use on import at startup (so say only import settings) var startupGroup = string.Empty; var importStartupNode = node.Element("ImportAtStartup"); if (importStartupNode != null) { startupGroup = importStartupNode.Attribute("Group").ValueOrDefault(startupGroup); } settings.ImportAtStartupGroup = ValueFromWebConfigOrDefault("ImportAtStartup.Group", startupGroup); settings.ExportAtStartup = ValueFromWebConfigOrDefault("ExportAtStartup", node.Element("ExportAtStartup").ValueOrDefault(false)); settings.ExportOnSave = ValueFromWebConfigOrDefault("ExportOnSave", node.Element("ExportOnSave").ValueOrDefault(true)); settings.UseGuidNames = ValueFromWebConfigOrDefault("UseGuidFilenames", node.Element("UseGuidFilenames").ValueOrDefault(false)); settings.ReportDebug = node.Element("ReportDebug").ValueOrDefault(false); settings.AddOnPing = node.Element("AddOnPing").ValueOrDefault(true); settings.RebuildCacheOnCompletion = node.Element("RebuildCacheOnCompletion").ValueOrDefault(false); settings.FailOnMissingParent = node.Element("FailOnMissingParent").ValueOrDefault(true); settings.ShowVersionCheckWarning = node.Element("ShowVersionCheckWarning").ValueOrDefault(true); settings.CacheFolderKeys = node.Element("CacheFolderKeys").ValueOrDefault(true); settings.EnableHistory = node.Element("EnableHistory").ValueOrDefault(true); settings.SignalRRoot = ValueFromWebConfigOrDefault("SignalRRoot", node.Element("SignalRRoot") .ValueOrDefault("backoffice/signalr/hubs")) .TrimStart(new[] { '/' }); settings.DefaultHandlerSettings = LoadKeyValueSettings(node.Element("HandlerDefaults")); // load the handlers var handlerSets = node.Element("HandlerSets"); if (handlerSets != null) { settings.HandlerSets = LoadHandlerSets(handlerSets, settings, out string defaultSet); settings.DefaultSet = defaultSet; } else { var handlers = node.Element("Handlers"); if (handlers != null) { // old config, load as default :( settings.HandlerSets = new List <HandlerSet>(); var defaultSet = LoadSingleHandlerSet(handlers, settings); settings.HandlerSets.Add(defaultSet); } } settings.CustomMappings = LoadAppKeysFromNode(node, "Mappings", true); // fire the loaded event, so things can tell when they are loaded. Reloaded?.Invoke(settings); return(settings); }