public void Configure(IAppHost appHost) { Log.Debug("starting DiskAnalysisServicesPlugin.Configure"); // Populate this Plugin's Application Configuration Settings // Location of the files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings var pluginAppSettings = new MultiAppSettingsBuilder() // Command line flags have highest priority // next in priority are Environment variables //.AddEnvironmentalVariables() // next in priority are Configuration settings in a text file relative to the current working directory at the point in time when this method executes. .AddTextFile(pluginSettingsTextFileName) // Builtin (compiled in) have the lowest priority .AddDictionarySettings(DefaultConfiguration.Configuration()) .Build(); // Key names in the cache for Configuration settings for a Plugin consist of the namespace and the string .Config // Key names in the appSettings of a Plugin for Configuration settings may or may not have the prefix // Compare the two lists of Configuration setting keys... // create a copy of the keys from AppSettings ensuring all are prefixed with the namespace and .Config var configKeyPrefix = myNamespace + ".Config."; var lengthConfigKeyPrefix = configKeyPrefix.Length; var appSettingsConfigKeys = pluginAppSettings.GetAllKeys(); var fullAppSettingsConfigKeys = appSettingsConfigKeys.Select(x => x.IndexOf(configKeyPrefix) >= 0 ? x : configKeyPrefix + x); // Get this namespaces configuration settings from the cache var cacheClient = appHost.GetContainer().Resolve <ICacheClient>(); var cacheConfigKeys = cacheClient.GetKeysStartingWith(configKeyPrefix); // Compare the configuration retrieved from the cache with the configuration from the built-in defaults, the text files, and the environment variables // If the cache is missing a ConfigKey, update the cache with the ConfigKey and its value from the appSettings var excludedConfigKeys = new HashSet <string>(cacheConfigKeys); var additionalConfigKeys = fullAppSettingsConfigKeys.Where(ck => !excludedConfigKeys.Contains(ck)); foreach (var ck in additionalConfigKeys) { cacheClient.Set <string>(ck, pluginAppSettings.GetString(ck.Substring(lengthConfigKeyPrefix))); } // If both the cache and the appSettings have the same ConfigKey, and the same value, do nothing // If both the cache and the appSettings have the same ConfigKey, and the values are different, // If the cache has a ConfigKey and the appSettings does not have that ConfigKey // Set a flag indicating the need to dialog with the user to resolve the cache vs. appSettings discrepancies bool configurationsMatch = true; // (appSettingsConfigkeys.Count == cacheConfigkeys.Count) ; // Populate this Plugin's Gateways // Location of the files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings //var pluginGateways = new MultiGatewaysBuilder() // Command line flags have highest priority // next in priority are Environment variables //.AddEnvironmentalVariables() // next in priority are Configuration settings in a text file relative to the current working directory at the point in time when this method executes. //.AddTextFile(pluginGatewaysTextFileName) // Builtin (compiled in) have the lowest priority //.AddDictionarySettings(DefaultGateways.Configuration()) //.Build(); // Create a Gateways collection from the txt file //ConcurrentObservableDictionary<string, IGateway> gateways = new ConcurrentObservableDictionary<string, IGateway>(); //gateways.Add("GoogleMapsGeoCoding", new GatewayBuilder().Build()); // Create the Plugin's data structure. There should only be a single instance. // Every Property matching a ConfigKey gets/sets the value of the matching ConfigKey in the cache // ConfigKey Properties do not have to be set in the constructor because the cache was setup before calling the constructor DiskAnalysisServicesData diskAnalysisServicesData = new DiskAnalysisServicesData(appHost, new ConcurrentObservableDictionary <string, decimal>(), onPluginRootCollectionChanged, onPluginRootPropertyChanged); // copy the most recent configuration settings to the Data // hmm should be a way to make sure the Data has a Property for each configuration setting, and to populate the initial Data with the cache value // DiskAnalysisServicesData.GoogleAPIKeyEncrypted = cacheClient.Get<string>(configKeyPrefix + "GoogleAPIKeyEncrypted"); //DiskAnalysisServicesData.HomeAwayAPIKeyEncrypted = cacheClient.Get<string>(configKeyPrefix + "HomeAwayAPIKeyEncrypted"); //DiskAnalysisServicesData.HomeAway_API_URI = cacheClient.Get<string>(configKeyPrefix + "HomeAway_API_URI"); // DiskAnalysisServicesData.Google_API_URI = cacheClient.Get<string>(configKeyPrefix + "Google_API_URI"); //DiskAnalysisServicesData.UriHomeAway_API_URI = cacheClient.Get<Uri>(configKeyPrefix + "UriHomeAway_API_URI"); //DiskAnalysisServicesData.UriGoogle_API_URI = cacheClient.Get<Uri>(configKeyPrefix + "UriGoogle_API_URI"); // and pass the Plugin's data structure to the container so it will be available to every other module and services appHost.GetContainer().Register(c => diskAnalysisServicesData); // ToDo: enable the mechanisms that monitors each GUI-specific data sensor, and start them running }
public void Configure(IAppHost appHost) { Log.Debug("starting GUIServicesPlugin.Configure"); // Populate this Plugin's Application Configuration Settings // Location of the files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings var pluginAppSettings = new MultiAppSettingsBuilder() // Environment variables have highest priority //.AddEnvironmentalVariables() // Configuration settings in a text file relative to the current working directory at the point in time when this method executes. .AddTextFile(pluginSettingsTextFileNameString) // Builtin (compiled in) have the lowest priority .AddDictionarySettings(DefaultConfiguration.Configuration()) .Build(); // tell ServiceStack where to find the physical base of the GUI static files // In RELEASE mode, the physical path of the root of the GUI should be located in a subdirectory relative to the location of the assembly that holds Program // In DEBUG mode, the physical path of the root of the GUI will be located somewhere "above and to the side" of the ServiceStack Plugin project string physicalRootPath = Path .GetDirectoryName( Assembly .GetExecutingAssembly() .Location); Log.Debug($"in GUIServicesPlugin.Configure, initial physicalRootPath (GetExecutingAssembly().Location) = {physicalRootPath}"); string relativeRootPathValue; #if DEBUG // set the physicalRootPath of the GUI code to the appSetting for the development RelativeRootPathKey relative to the location of this plugin's assembly // verify key exists, else throw exception if (!pluginAppSettings.Exists(debugRelativeRootPathKey) || (pluginAppSettings.GetString(debugRelativeRootPathKey) == string.Empty)) { throw new Exception(debugRelativeRootPathKeyOrValueNotFoundExceptionMessage); } relativeRootPathValue = pluginAppSettings.GetString(debugRelativeRootPathKey); #else // set the physicalRootPath of the GUI code to the appSetting for the production RelativeRootPathKey relative to the location of this plugin's assembly // verify key exists, else throw exception if (!pluginAppSettings.Exists(productionRelativeRootPathKey) || (pluginAppSettings.GetString(productionRelativeRootPathKey) == "")) { throw new Exception(productionRelativeRootPathKeyOrValueNotFoundExceptionMessage); } relativeRootPathValue = pluginAppSettings.GetString(productionRelativeRootPathKey); #endif Log.Debug($"in GUIServicesPlugin.Configure, relativeRootPathValue = {relativeRootPathValue}"); // Use these for checking for invalid characters in the appSettings RelativeRootPath values char[] invalidChars = Path.GetInvalidPathChars(); bool valid = !relativeRootPathValue.Any(x => invalidChars.Contains(x)); if (!valid) { throw new Exception(relativeRootPathValueContainsIlegalCharacterExceptionMessage); } Log.Debug($"in GUIServicesPlugin.Configure, physicalRootPath = {physicalRootPath}, relativeRootPathValue = {relativeRootPathValue}"); physicalRootPath = PathUtils.CombinePaths(physicalRootPath, relativeRootPathValue); Log.Debug($"in GUIServicesPlugin.Configure, "); // use an appSetting for the VirtualRootPath string virtualRootPath; // verify key exists, else throw exception. String.Empty is allowed if (!pluginAppSettings.Exists(virtualRootPathKey)) { throw new Exception(virtualRootPathKeyOrValueNotFoundExceptionMessage); } virtualRootPath = pluginAppSettings.GetString(virtualRootPathKey); // Map the Virtual root Dir to the physical path of the root of the GUI // Wrap in a try catch block in case the root Path does not exist try { appHost.AddVirtualFileSources .Add(new FileSystemMapping(virtualRootPath, physicalRootPath)); } catch { throw; // ToDo: figure out how to log this and fallback to something useful } Log.Debug($"in GUIServicesPlugin.Configure, virtualRootPath = {virtualRootPath}"); // Blazor requires the delivery of static files ending in certain file suffixes. // SS disallows many of these by default, so here we tell SS to allow certain file suffixes appHost.Config.AllowFileExtensions.Add("dll"); appHost.Config.AllowFileExtensions.Add("json"); appHost.Config.AllowFileExtensions.Add("pdb"); // per conversation with Myth at SS, the default behaviour, for URi "/" is to return the content of wwwroot/index.html appHost.Config.DefaultRedirectPath = "/index.html"; // ToDo: if the GUI configuration specifies that the GUI has GUI-specific data sensor that can and should be monitored, attach the event handlers that will respond to changes in the monitored data structures // ToDo: setup the mechanisms that monitors the GUI // create the plugIn's data object and pass it to the container so it will be available to every other module and services appHost.GetContainer() .Register <GUIServicesData>(d => new GUIServicesData(pluginAppSettings)); // ToDo: enable the mechanisms that monitors each GUI-specific data sensor, and start them running }