/// <summary> /// Gets the names of the configured assemblies from configuration. /// </summary> /// <returns> /// A <see cref="System.Collections.Specialized.StringCollection"/> with /// the names of the configured assemblies that should participate in this /// path provider. /// </returns> /// <seealso cref="GSF.Web.Hosting.EmbeddedResourcePathProvider" /> protected static string[] GetConfiguredAssemblyNames() { CategorizedSettingsElement setting = ConfigurationFile.Current.Settings["EmbeddedResourceProvider"]["EmbeddedResourceAssemblies"]; if ((object)setting == null) { return new string[] { } } ; return(setting.Value.Split(',')); }
// Initiates the search for the archive location. // This will check the configuration file setting before // resorting to the registry or searching well-known locations. private void InitializeArchiveLocation() { CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; CategorizedSettingsElement archiveLocationSetting = systemSettings["ArchiveLocation"]; if ((object)archiveLocationSetting != null) { m_archiveLocation = FilePath.GetAbsolutePath(archiveLocationSetting.Value); } if (string.IsNullOrEmpty(m_archiveLocation) && !TryLocateArchive(out m_archiveLocation)) { throw new DirectoryNotFoundException($"Unable to locate {m_archiveName.ToNonNullString().ToUpper()} archive. Please check the configuration file to set the archive location."); } }
/// <summary> /// Caches meta-data locally. /// </summary> /// <param name="metadata">Source time-series metadata object to cache.</param> /// <param name="topic">Kafka topic.</param> /// <param name="statusMessage">Status message function.</param> public static void CacheLocally(TimeSeriesMetadata metadata, string topic, Action <string> statusMessage) { // Cache meta-data locally so it can be reviewed string cacheFileName = "undefined"; try { // Define default cache path string cachePath = null; try { // Attempt to retrieve configuration cache path as defined in the config file ConfigurationFile configFile = ConfigurationFile.Current; CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; CategorizedSettingsElement configurationCachePathSetting = systemSettings["ConfigurationCachePath"]; if ((object)configurationCachePathSetting != null) { cachePath = FilePath.GetAbsolutePath(systemSettings["ConfigurationCachePath"].Value); } if (string.IsNullOrEmpty(cachePath)) { cachePath = $"{FilePath.GetAbsolutePath("")}{Path.DirectorySeparatorChar}ConfigurationCache{Path.DirectorySeparatorChar}"; } } catch (ConfigurationErrorsException) { cachePath = $"{FilePath.GetAbsolutePath("")}{Path.DirectorySeparatorChar}ConfigurationCache{Path.DirectorySeparatorChar}"; } cacheFileName = Path.Combine(cachePath, $"{topic}.xml"); using (FileStream stream = File.Create(cacheFileName)) Serialize(metadata, stream, false); } catch (Exception ex) { statusMessage?.Invoke($"WARNING: Failed to locally cache current metadata to \"{cacheFileName}\": {ex.Message}"); } }
/// <summary> /// Saves <see cref="HistorianMetadataService"/> settings to the config file if the <see cref="RestService.PersistSettings"/> property is set to true. /// </summary> public override void SaveSettings() { base.SaveSettings(); if (PersistSettings) { // Ensure that settings category is specified. if (string.IsNullOrEmpty(SettingsCategory)) { throw new InvalidOperationException("SettingsCategory property has not been set"); } // Save settings under the specified category. ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElement element = null; CategorizedSettingsElementCollection settings = config.Settings[SettingsCategory]; element = settings["ConnectionString", true]; element.Update(m_connectionString, element.Description, element.Encrypted); config.Save(); } }
/// <summary> /// Removes a <see cref="CategorizedSettingsElement"/> object if it exists. /// </summary> /// <param name="setting">The <see cref="CategorizedSettingsElement"/> object to remove.</param> public void Remove(CategorizedSettingsElement setting) { if (base.BaseIndexOf(setting) >= 0) { Remove(setting.Name); } }
/// <summary> /// Adds a new <see cref="CategorizedSettingsElement"/> object if one does not exist. /// </summary> /// <param name="setting">The <see cref="CategorizedSettingsElement"/> object to add.</param> public void Add(CategorizedSettingsElement setting) { if (base.BaseGet(setting.Name) == null) { // Adds the element only if it does not exist. setting.SetCryptoKey(m_cryptoKey); base.BaseAdd(setting); } }
/// <summary> /// Gets the index of the specified <see cref="CategorizedSettingsElement"/> object. /// </summary> /// <param name="setting">The <see cref="CategorizedSettingsElement"/> object whose index is to be retrieved.</param> /// <returns>Index of the specified <see cref="CategorizedSettingsElement"/> object if found; otherwise -1.</returns> public int IndexOf(CategorizedSettingsElement setting) { return base.BaseIndexOf(setting); }
/// <summary> /// Creates an instance of <see cref="App"/> class. /// </summary> public App() { bool mirrorMode = true; AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); m_errorLogger = new ErrorLogger(); m_defaultErrorText = m_errorLogger.ErrorTextMethod; m_errorLogger.ErrorTextMethod = ErrorText; m_errorLogger.ExitOnUnhandledException = false; m_errorLogger.HandleUnhandledException = true; m_errorLogger.LogToEmail = false; m_errorLogger.LogToEventLog = true; m_errorLogger.LogToFile = true; m_errorLogger.LogToScreenshot = true; m_errorLogger.LogToUI = true; m_errorLogger.Initialize(); m_title = AssemblyInfo.EntryAssembly.Title; // Setup default cache for measurement keys and associated Guid based signal ID's AdoDataConnection database = null; try { database = new AdoDataConnection(CommonFunctions.DefaultSettingsCategory); MeasurementKey.EstablishDefaultCache(database.Connection, database.AdapterType); } catch (Exception ex) { // First attempt to display a modal dialog will fail to block this // thread -- modal dialog displayed by the error logger will block now MessageBox.Show(ex.Message); // Log and display error, then exit application - manager must connect to database to continue m_errorLogger.Log(new InvalidOperationException(string.Format("{0} cannot connect to database: {1}", m_title, ex.Message), ex), true); } finally { if (database != null) { database.Dispose(); } } try { CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; CategorizedSettingsElement mirrorModeSetting = systemSettings["MirrorMode"]; if ((object)mirrorModeSetting != null) { mirrorMode = mirrorModeSetting.ValueAsBoolean(); } } catch (Exception ex) { // First attempt to display a modal dialog will fail to block this // thread -- modal dialog displayed by the error logger will block now MessageBox.Show(ex.Message); // Log and display error, but continue on - if manager fails to load MirrorMode from the config file, it can just fall back on the default m_errorLogger.Log(new InvalidOperationException(string.Format("{0} cannot access mirror mode setting in configuration file - defaulting to true: {1}", m_title, ex.Message), ex)); } IsolatedStorageManager.WriteToIsolatedStorage("MirrorMode", mirrorMode); }
/// <summary> /// Adds a new <see cref="CategorizedSettingsElement"/> object if one does not exist. /// </summary> /// <param name="name">Name of the <see cref="CategorizedSettingsElement"/> object.</param> /// <param name="value">Value of the <see cref="CategorizedSettingsElement"/> object.</param> /// <param name="description">Description of the <see cref="CategorizedSettingsElement"/> object.</param> /// <param name="encryptValue">true if the Value of <see cref="CategorizedSettingsElement"/> object is to be encrypted; otherwise false.</param> /// <param name="scope">One of the <see cref="SettingScope"/> values.</param> public void Add(string name, object value, string description, bool encryptValue, SettingScope scope) { if ((object)base.BaseGet(name) == null) { // Add the element only if it does not exist. CategorizedSettingsElement setting = new CategorizedSettingsElement(this, name); setting.Update(value, description, encryptValue, scope); Add(setting); } }
/// <summary> /// Creates an instance of <see cref="App"/> class. /// </summary> public App() { string systemName = null; AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); Application.Current.SessionEnding += Application_SessionEnding; try { string getElementValue(XElement[] elements, string name) { XElement element = elements.Elements("add").FirstOrDefault(elem => elem.Attributes("name").Any(nameAttribute => string.Compare(nameAttribute.Value, name, StringComparison.OrdinalIgnoreCase) == 0)); return(element?.Attributes("value").FirstOrDefault()?.Value); } string configPath = FilePath.GetAbsolutePath(ConfigurationFile.Current.Configuration.FilePath.Replace("Manager", "")); if (File.Exists(configPath)) { XDocument hostConfig = XDocument.Load(configPath); XElement[] systemSettings = hostConfig.Descendants(SystemSettings).ToArray(); // Get system name from host service config systemName = getElementValue(systemSettings, "SystemName"); // Validate manager database connection as compared to host service string hostConnectionString = getElementValue(systemSettings, "ConnectionString"); string hostDataProviderString = getElementValue(systemSettings, "DataProviderString"); string hostNodeID = getElementValue(systemSettings, "NodeID"); ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection configSettings = config.Settings[SystemSettings]; configSettings.Add("KeepCustomConnection", "false", "Determines if manager should keep custom database connection setting separate from host service."); if (!configSettings["KeepCustomConnection"].Value.ParseBoolean()) { MethodInfo getRawValueMethod = typeof(CategorizedSettingsElement).GetMethod("GetRawValue", BindingFlags.Instance | BindingFlags.NonPublic); string getRawValue(CategorizedSettingsElement element) { if (getRawValueMethod is null) { return(element.Value); } return(getRawValueMethod.Invoke(element, Array.Empty <object>()) as string); } // Get value from connection string that is still encrypted for proper comparison string connectionString = getRawValue(configSettings["ConnectionString"]); string dataProviderString = configSettings["DataProviderString"].Value; string nodeID = configSettings["NodeID"].Value; if (!hostConnectionString.Equals(connectionString, StringComparison.OrdinalIgnoreCase) || !hostDataProviderString.Equals(dataProviderString, StringComparison.OrdinalIgnoreCase) || !hostNodeID.Equals(nodeID, StringComparison.OrdinalIgnoreCase)) { bool mismatchHandled = false; if (Environment.CommandLine.Contains("-elevated") && Environment.CommandLine.Contains("-connection")) { if (Environment.CommandLine.Contains("-connectionFix")) { configSettings["ConnectionString"].Value = hostConnectionString; configSettings["DataProviderString"].Value = hostDataProviderString; configSettings["NodeID"].Value = hostNodeID; config.Save(); mismatchHandled = true; } else if (Environment.CommandLine.Contains("-connectionKeep")) { configSettings["KeepCustomConnection"].Value = "true"; config.Save(); mismatchHandled = true; } } if (!mismatchHandled) { bool correctMismatch = System.Windows.Forms.MessageBox.Show(new NativeWindow(), "Manager database connection does not match host service. Do you want to correct this?", "Database Mismatch", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; string elevatedOperation = correctMismatch ? "-connectionFix" : "-connectionKeep"; ProcessStartInfo startInfo = new ProcessStartInfo { FileName = Environment.GetCommandLineArgs()[0], Arguments = $"{string.Join(" ", Environment.GetCommandLineArgs().Skip(1))} -elevated {elevatedOperation}", UseShellExecute = true, Verb = "runas" }; using (Process.Start(startInfo)) { } Environment.Exit(0); } } } } } catch { // If this fails, it's not a huge deal } m_errorLogger = new ErrorLogger { ErrorTextMethod = ErrorText, ExitOnUnhandledException = false, HandleUnhandledException = true, LogToEmail = false, LogToEventLog = true, LogToFile = true, LogToScreenshot = true, LogToUI = true }; m_errorLogger.Initialize(); m_defaultErrorText = m_errorLogger.ErrorTextMethod; Title = AssemblyInfo.EntryAssembly.Title; // Add system name to title if (!string.IsNullOrWhiteSpace(systemName)) { Title = $"{Title} [{systemName.Trim()}]"; } // Setup default cache for measurement keys and associated Guid based signal ID's AdoDataConnection database = null; try { database = new AdoDataConnection(SystemSettings); if (!Environment.CommandLine.Contains("-elevated")) { ConfigurationFile configurationFile = ConfigurationFile.Current; CategorizedSettingsElementCollection systemSettings = configurationFile.Settings[SystemSettings]; string elevateSetting = systemSettings["ElevateProcess"]?.Value; bool elevateProcess = !string.IsNullOrEmpty(elevateSetting) ? elevateSetting.ParseBoolean() : database.IsSqlite; if (elevateProcess) { ProcessStartInfo startInfo = new ProcessStartInfo { FileName = Environment.GetCommandLineArgs()[0], Arguments = $"{string.Join(" ", Environment.GetCommandLineArgs().Skip(1))} -elevated", UseShellExecute = true, Verb = "runas" }; using (Process.Start(startInfo)) { } Environment.Exit(0); } } MeasurementKey.EstablishDefaultCache(database.Connection, database.AdapterType); } catch (Exception ex) { // First attempt to display a modal dialog will fail to block this // thread -- modal dialog displayed by the error logger will block now MessageBox.Show(ex.Message); // Log and display error, then exit application - manager must connect to database to continue m_errorLogger.Log(new InvalidOperationException($"{Title} cannot connect to database: {ex.Message}", ex), true); } finally { database?.Dispose(); } bool mirrorMode = true; try { CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; CategorizedSettingsElement mirrorModeSetting = systemSettings["MirrorMode"]; if (!(mirrorModeSetting is null)) { mirrorMode = mirrorModeSetting.ValueAsBoolean(); } } catch (Exception ex) { // First attempt to display a modal dialog will fail to block this // thread -- modal dialog displayed by the error logger will block now MessageBox.Show(ex.Message); // Log and display error, but continue on - if manager fails to load MirrorMode from the config file, it can just fall back on the default m_errorLogger.Log(new InvalidOperationException($"{Title} cannot access mirror mode setting in configuration file - defaulting to true: {ex.Message}", ex)); } IsolatedStorageManager.WriteToIsolatedStorage("MirrorMode", mirrorMode); }
/// <summary> /// Reads XML from the configuration file. /// </summary> /// <param name="reader">The <see cref="System.Xml.XmlReader"/> object, which reads from the configuration file.</param> protected override void DeserializeSection(XmlReader reader) { using (BlockAllocatedMemoryStream configSectionStream = new BlockAllocatedMemoryStream()) { XmlDocument configSection = new XmlDocument(); configSection.Load(reader); configSection.Save(configSectionStream); // Adds all the categories that are under the categorizedSettings section of the configuration file // to the property collection. Again, this is essentially doing what marking a property with the // <ConfigurationProperty()> attribute does. If this is not done, then an exception will be raised // when the category elements are being deserialized. if ((object)configSection.DocumentElement != null) { XmlNodeList categories = configSection.DocumentElement.SelectNodes("*"); if ((object)categories != null) { foreach (XmlNode category in categories) { ConfigurationProperty configProperty = new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection)); base.Properties.Add(configProperty); if ((object)m_sections != null) { CategorizedSettingsElementCollection settingsCategory = new CategorizedSettingsElementCollection { Name = category.Name, Section = this, }; settingsCategory.SetCryptoKey(m_cryptoKey); m_sections.Add(category.Name, settingsCategory); // Read all elements within this category section XmlNodeList elements = category.SelectNodes("*"); SettingScope scope; if ((object)elements != null) { foreach (XmlNode element in elements) { CategorizedSettingsElement categorySetting = new CategorizedSettingsElement(settingsCategory); categorySetting.Name = element.GetAttributeValue("name"); categorySetting.Value = element.GetAttributeValue("value"); categorySetting.Description = element.GetAttributeValue("description") ?? ""; categorySetting.Encrypted = element.GetAttributeValue("encrypted").ToNonNullNorWhiteSpace("false").ParseBoolean(); if (Enum.TryParse(element.GetAttributeValue("scope").ToNonNullNorWhiteSpace("Application"), out scope)) categorySetting.Scope = scope; else categorySetting.Scope = SettingScope.Application; settingsCategory.Add(categorySetting); } } } } } } m_sectionLoaded = true; if ((object)m_sections == null) { configSectionStream.Seek(0, SeekOrigin.Begin); base.DeserializeSection(XmlReader.Create(configSectionStream)); } } }
/// <summary> /// Adds a new <see cref="CategorizedSettingsElement"/> object if one does not exist. /// </summary> /// <param name="setting">The <see cref="CategorizedSettingsElement"/> object to add.</param> public void Add(CategorizedSettingsElement setting) { if ((object)base.BaseGet(setting.Name) == null) { // Add the element only if it does not exist. setting.Category = this; setting.SetCryptoKey(m_cryptoKey); base.BaseAdd(setting); Modified = true; } }
// Static Methods /// <summary> /// Loads the <see cref="AdoSecurityCache"/> for the current local user. /// </summary> /// <returns>Loaded instance of the <see cref="AdoSecurityCache"/>.</returns> public static AdoSecurityCache GetCurrentCache() { AdoSecurityCache currentCache; AdoSecurityCache localSecurityCache = null; // Define default cache path string cachePath = null; try { // Attempt to retrieve configuration cache path as defined in the config file ConfigurationFile configFile = ConfigurationFile.Current; CategorizedSettingsElementCollection systemSettings = configFile.Settings["systemSettings"]; CategorizedSettingsElement configurationCachePathSetting = systemSettings["ConfigurationCachePath"]; if ((object)configurationCachePathSetting != null) { cachePath = FilePath.GetAbsolutePath(systemSettings["ConfigurationCachePath"].Value); } if (string.IsNullOrEmpty(cachePath)) { cachePath = string.Format("{0}{1}ConfigurationCache{1}", FilePath.GetAbsolutePath(""), Path.DirectorySeparatorChar); } } catch (ConfigurationErrorsException) { cachePath = string.Format("{0}{1}ConfigurationCache{1}", FilePath.GetAbsolutePath(""), Path.DirectorySeparatorChar); } string localCacheFileName = Path.Combine(cachePath, DefaultCacheFileName); try { // Make sure configuration cache path exists if (!Directory.Exists(cachePath)) { Directory.CreateDirectory(cachePath); } // Initialize local ADO security cache (application may only have read-only access to this cache) localSecurityCache = new AdoSecurityCache { FileName = localCacheFileName, ReloadOnChange = false, AutoSave = false }; // Load initial ADO security data set localSecurityCache.Load(); // Validate that current user has write access to the local cache folder string tempFile = FilePath.GetDirectoryName(localCacheFileName) + Guid.NewGuid() + ".tmp"; using (File.Create(tempFile)) { } if (File.Exists(tempFile)) { File.Delete(tempFile); } // No access issues exist, use local cache as the primary cache currentCache = localSecurityCache; currentCache.AutoSave = true; localSecurityCache = null; } catch (UnauthorizedAccessException) { // User does not have needed serialization access to common cache folder, // use a path where user will have rights string userCacheFolder = FilePath.AddPathSuffix(FilePath.GetApplicationDataFolder()); string userCacheFileName = userCacheFolder + FilePath.GetFileName(localCacheFileName); // Make sure user directory exists if (!Directory.Exists(userCacheFolder)) { Directory.CreateDirectory(userCacheFolder); } // Copy existing common cache if none exists if (File.Exists(localCacheFileName) && !File.Exists(userCacheFileName)) { File.Copy(localCacheFileName, userCacheFileName); } // Initialize primary cache within user folder currentCache = new AdoSecurityCache { FileName = userCacheFileName, ReloadOnChange = false, AutoSave = true }; // Load initial ADO security data set currentCache.Load(); // Update user located security cache if locally located security cache is newer if ((object)localSecurityCache != null && File.Exists(localCacheFileName) && File.Exists(userCacheFileName) && File.GetLastWriteTime(localCacheFileName) > File.GetLastWriteTime(userCacheFileName)) { currentCache.DataSet = localSecurityCache.DataSet; } } if ((object)localSecurityCache != null) { localSecurityCache.Dispose(); } return(currentCache); }