public override void Configure(Funq.Container container) { AppSettings = new MultiAppSettingsBuilder() .AddEnvironmentalVariables() .AddTextFile("~/settings.txt".MapAbsolutePath()) .Build(); var useRabbitMq = AppSettings.Get("rabbitmq:enable", false); if (useRabbitMq) { var rabbitMqConnectionString = AppSettings.Get("rabbitmq:connectionString", "localhost:5672"); var rabbitMqUserName = AppSettings.Get <string>("rabbitmq:userName", null); var rabbitMqPassword = AppSettings.Get <string>("rabbitmq:passWord", null); container.Register <ICommandQueueService>(c => new RabbitCommandQueueService(rabbitMqConnectionString, rabbitMqUserName, rabbitMqPassword)); var rabbitMqAlertConnectionString = AppSettings.Get("rabbitmqalert:connectionString", "localhost:5673"); var rabbitMqAlertUserName = AppSettings.Get <string>("rabbitmqalert:userName", null); var rabbitMqAlertPassword = AppSettings.Get <string>("rabbitmqalert:passWord", null); container.Register <IAlertQueueService>(c => new RabbitAlertQueueService(rabbitMqAlertConnectionString, rabbitMqAlertUserName, rabbitMqAlertPassword)); } else { container.Register <ICommandQueueService>(c => new CommandQueueService()); container.Register <IAlertQueueService>(c => new AlertQueueService()); } }
public TestAppHost() : base(nameof(IntegrationTest), typeof(DeploymentService).Assembly) { var versionsJsv = new List <Version> { new Version { VersionNumber = "3.5.3", DownloadUrl = "https://neo4j.com/artifact.php?name=neo4j-community-3.5.3-windows.zip", ZipFileName = "neo4j-community-3.5.3-windows.zip", Architecture = "V3" } }.ToJsv(); AppSettings = new MultiAppSettingsBuilder() .AddDictionarySettings(new Dictionary <string, string> { { AppSettingsKeys.Versions, versionsJsv }, { AppSettingsKeys.Neo4jBasePath, @"c:\Neo4jManager" }, { AppSettingsKeys.StartBoltPort, "7691" }, { AppSettingsKeys.StartHttpPort, "7401" }, { AppSettingsKeys.WatchDogInterval, "00:01:00" }, { AppSettingsKeys.DefaultLeasePeriod, "00:05:00" }, { AppSettingsKeys.ExpiryPeriod, "00:05:00" }, }) .Build(); }
public AppHost(IWebHostEnvironment webHostEnvironment) : base("Neo4jManager", typeof(DeploymentService).Assembly) { var versions = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "versions.json")) .FromJson <IEnumerable <Version> >() .ToJsv(); AppSettings = new MultiAppSettingsBuilder() .AddEnvironmentalVariables() .AddTextFile(Path.Combine(AppContext.BaseDirectory, "app.settings")) .AddDictionarySettings(new Dictionary <string, string> { { AppSettingsKeys.Versions, versions } }) .Build(); }
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 }
/// <summary> /// Application specific configuration /// This method should initialize any IoC resources utilized by your web service classes. /// </summary> public override void Configure(Container container) { // inject the concrete logging implementation Log.Debug($"Entering AppHost.Configure method, container is {container.ToString()}"); // AppSettings is a first class object on the Container, so it will be auto-wired // In any other assembly, AppSettings is read-only, so it must be populated in this assembly // Location of the configuration files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings //It would be nice if ServiceStack implemented the User Secrets pattern that ASP Core provides // The Environment variable may define the location of a text file to add to the AppSettings string indirectSettingsTextFilepath; try { indirectSettingsTextFilepath = Environment.GetEnvironmentVariable(agentEnvironmentIndirectSettingsTextFileNameKey); } catch (SecurityException e) { Log.Error($"{cannotReadEnvironmentVariablesSecurityExceptionMessage}: {e.Message}"); throw new SecurityException(cannotReadEnvironmentVariablesSecurityExceptionMessage, e); } // ToDo: If the Environment variable does define a location for another text fle, ensure it can be read if (indirectSettingsTextFilepath != null) { try { } catch { } } // Create the AppSettingsBuilder, and add command line arguments to it var multiAppSettingsBuilder = new MultiAppSettingsBuilder(); // Highest priority is any command line variable values, so add command line arguments to the AppSettingsBuilder // ToDo: .Add?? // Next in priority are all environment values, so append AddEnvironmentalVariables to the AppSettingsBuilder multiAppSettingsBuilder.AddEnvironmentalVariables(); // Next in priority are contents of any indirect files mentioned in the environment variables (e.g. User Secrets ) if (indirectSettingsTextFilepath != null) { multiAppSettingsBuilder.AddTextFile(indirectSettingsTextFilepath); } // Next in priority are any configuration settings in a text file named on the command line. // ToDo: if a configuration settings text file is specified on the command line, ensure we have permission to read it // ToDo: append AddTextFile for configuration settings in a text file specified on the command line to the AppSettingsBuilder // Next in priority are any configuration settings in a text file named as a constant string in the app. // Location of the text file is relative to the current working directory at the point in time when this method executes. // If this file does not exist, it is not considered an error, but if it does exist, not having read permission is an error // ToDo: if a configuration settings text file is specified as a constant string in the app, ensure we have permission to read it // ToDo: if it exists, append AddTextFile for configuration settings in a text file specified as a constant string in the app to the AppSettingsBuilder multiAppSettingsBuilder.AddTextFile(agentSettingsTextFileNameString); // Next in priority are any configuration settings in the application config file (AKA AceAgent.exe.config at runtime) // Location of the application config file is relative to the current working directory at the point in time when this method executes. // If this file does not exist, it is not considered an error, but if it does exist, not having read permission is an error // ToDo: if a application config file is specified as a constant string in the app, ensure we have permission to read it // ToDo: if it exists, append AddTextFile for configuration settings in a text file specified as a constant string in the app to the AppSettingsBuilder multiAppSettingsBuilder.AddAppSettings() // Builtin (compiled in) configuration settings have the lowest priority // Add these to the AppSettingsBuilder .AddDictionarySettings(DefaultConfiguration.Configuration()); //Build the AppSettings AppSettings = multiAppSettingsBuilder.Build(); // Create the BaseServices data structure and register it in the container // The AppHost (here, ServiceStack running as a Windows service) has some configuration that is common // to both Frameworks (.Net and .Net Core), which will be setup in a common assembly, so this instance of // the appHost is being passed to the BaseServicesData constructor. // this also registers a BaseServicesData instance in the container // ToDo: implement Singleton pattern for BaseServicesData in the DI Container var baseServicesData = new BaseServicesData(this); container.Register <BaseServicesData>(c => baseServicesData); // ToDo: Get the list of plugins to install from the configuration settings, currently hard coded // Create the list of PlugIns to load var plugInList = new List <IPlugin>() { //new RealEstateServicesPlugin(), //new MinerServicesPlugin(), new DiskAnalysisServicesPlugin(), new GUIServicesPlugin() }; // Load each plugin here. foreach (var pl in plugInList) { Plugins.Add(pl); } // ToDo: See Issue #8 // ToDo place a static, deep-copy of the current application'instance of the configuration settings as the first object in the application's configuration settings history list. // start all the timers Log.Debug("In AppHost.Configure: starting all timers"); var timers = Container.Resolve <Dictionary <string, System.Timers.Timer> >(); var longRunningTasksCheckTimer = timers[Ace.Agent.BaseServices.BaseServicesData.LongRunningTasksCheckTimerName]; longRunningTasksCheckTimer.Start(); /* * // ToDo: create a NotifyIcon equivalent for a Windows Service or Linux Daemon. Notifiy Icon itself will not work, as that is for WinForms only * Log.Debug("in AppHost.Configure: Create a NotifyIcon for AceCommander"); * Application.EnableVisualStyles(); * Application.SetCompatibleTextRenderingDefault(false); * NotifyIcon notifyIcon1 = new NotifyIcon(); * ContextMenu contextMenu1 = new ContextMenu(); * MenuItem menuItem1 = new MenuItem(); * contextMenu1.MenuItems * .AddRange(new MenuItem[] { menuItem1 }); * menuItem1.Index=0; * menuItem1.Text="E&xit"; * menuItem1.Click+=new EventHandler(menuItem1_Click); * notifyIcon1.Icon=new Icon("atap.ico"); * notifyIcon1.Text="AceCommander"; * notifyIcon1.ContextMenu=contextMenu1; * notifyIcon1.Visible=true; * // Log.Debug("Calling a Web Forms Application instance's static Run method"); * // Application.Run(); * // notifyIcon1.Visible = false; * Log.Debug("NotifyIcon for AceCommander created"); */ Log.Debug("Leaving AppHost.Configure"); }
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 }
/// Configure its PlugInAppSettings and ConfigurationData public void BeforePluginsLoaded(IAppHost appHost) { // Get the IHostEnvironment type object from the ServiceStack Container HostEnvironment = appHost.GetContainer().Resolve <Microsoft.Extensions.Hosting.IHostEnvironment>(); // Determine the environment this PlugIn has been activated in string envName = HostEnvironment.EnvironmentName; // Populate this PlugIn's AppSettings Configuration Settings and place it in the appSettingsDictionary // ToDo: figure out how to place /resolve text files from relative to the location of the PlugIn assembly var pluginAppSettingsBuilder = new MultiAppSettingsBuilder(); // ToDo: command line settings have the highest priority // Environment variables have 2nd highest priority pluginAppSettingsBuilder.AddEnvironmentalVariables(); // third priority are Non-Production Configuration settings in a text file if (!this.HostEnvironment.IsProduction()) { var settingsTextFileName = Ace.Agent.GUIServices.StringConstants.PluginSettingsTextFileName + '.' + envName + StringConstants.PluginSettingsTextFileSuffix; // ToDo: ensure it exists and the ensure we have permission to read it // ToDo: Security: There is something called a Time-To-Check / Time-To-Use vulnerability, ensure the way we check then access the text file does not open the program to this vulnerability pluginAppSettingsBuilder.AddTextFile(settingsTextFileName); } // next in priority are Production Configuration settings in a text file pluginAppSettingsBuilder.AddTextFile(StringConstants.PluginSettingsTextFileName + StringConstants.PluginSettingsTextFileSuffix); // BuiltIn (compiled in) have the lowest priority pluginAppSettingsBuilder.AddDictionarySettings(DefaultConfiguration.Production); // Populate the PlugInAppSettings property for this PlugIn from the builder PlugInAppSettings = pluginAppSettingsBuilder.Build(); // Populate the ConfigurationData property with an empty configuration data instance // populate the GUIS property of the ConfigurationData with a new GUIS having an empty list of GUIs ConfigurationData = new ConfigurationData(); ConfigurationData.GUIS = new GUIS() { GUIs = new List <GUI>() }; // Get the GUIMaps POCO from PlugInAppSettings // Ensure the PlugInAppSettings has a non-empty ConfigKey for the GUIMaps if (!PlugInAppSettings.Exists(StringConstants.GUIMapsConfigKey) || (PlugInAppSettings.GetString(StringConstants.GUIMapsConfigKey) == string.Empty)) { throw new Exception(StringConstants.GUISKeyOrValueNotFoundExceptionMessage); } // ToDo: Security: this is a place where character strings from external sources are processed, check carefully // any typo in the text file can make the conversion to a POCO break GUIMaps gUIMaps; try { gUIMaps = PlugInAppSettings.Get <GUIMaps>(StringConstants.GUIMapsConfigKey); } catch (Exception) { //ToDo: Better exception handling throw; } // ToDo: Throw exception if the IEnumerable count = 0 char[] invalidChars = Path.GetInvalidPathChars(); // Loop over each GUI defined in pluginAppSettings GUIs, create a virtualFileMapping foreach (GUIMap gUIMap in gUIMaps._GUIMaps) { if (gUIMap.RelativeToContentRootPath.Any(x => invalidChars.Contains(x))) { throw new Exception(StringConstants.RelativeRootPathValueContainsIlegalCharacterExceptionMessage); } // The GenericHost's ContentRootPath is found on the HostEnvironment injected during the .ctor var physicalPath = Path.Combine(this.HostEnvironment.ContentRootPath, gUIMap.RelativeToContentRootPath); //Log.Debug("in GUIServicesPlugin.Configure, physicalPath = {PhysicalPath}, ContentRootPath = {ContentRootPath} relativeRootPathValue = {RelativeToContentRootPath}", physicalPath, this.HostEnvironment.ContentRootPath, gUIMap.RelativeToContentRootPath); //Log.Debug("in GUIServicesPlugin.Configure, index.html exists in physicalpath = {0}", File.Exists(Path.Combine(physicalPath, "index.html"))); //Log.Debug("in GUIServicesPlugin.Configure, virtualRootPath = {GUIMapVirtualRootPath}", gUIMap.VirtualRootPath); // if the VirtualRootPath is empty, setup the webserver's wwwroot to point to the physicalpath if (gUIMap.VirtualRootPath == null) { Log.Debug("current wwwroot = {Wwwroot}", (appHost as AppHostBase).HostingEnvironment.WebRootPath); // If the webserver's wwwroot is already populated, throw an exception // Set the WebRootPath to the physicalpath // (appHost as AppHostBase).HostingEnvironment.WebRootPath = physicalPath; // Log.Debug("current wwwroot = {Wwwroot}", (appHost as AppHostBase).HostingEnvironment.WebRootPath); appHost.AddVirtualFileSources .Add(new FileSystemMapping("", physicalPath)); } else { // Map the virtualRootPath to the physicalpath of the root of the GUI // Wrap in a try catch block in case the physicalRootPath does not exists // ToDo: test for failure condition instead of letting it throw an exception try { appHost.AddVirtualFileSources .Add(new FileSystemMapping(gUIMap.VirtualRootPath, physicalPath)); } catch (Exception e) { // ToDo: research how best to log an exception with Serilog, ServiceStack and/or MS // ToDo: USe stringconstant for exception message Log.Debug(e, "in GUIServicesPlugin.Configure, Adding a new VirtualFileSource failed with : {Message}", e.Message); // ToDo wrap in an Aggregate when doing loop throw; // ToDo: figure out how to log this and fallback to something useful } } // ToDo: Get Version and Description from assembly metadata ConfigurationData.GUIS.GUIs.Add(new GUI() { Version = "0.0.1", Description = "A sample", GUIMap = gUIMap }); } // ToDo: add support for probing for additional GUIS at runtime, add them to ConfigurationData.GUIS.GUIs // If a request comes in for the root of the web site, redirect it to the default GUI's index.html file // ToDo: Security: this is a place where character strings from external sources are processed, check carefully // Get the DefaultGUIVirtualRootPath from PlugInAppSettings // Ensure the PlugInAppSettings has a (possibly empty) ConfigKey for the DefaultGUIVirtualRootPath if (!PlugInAppSettings.Exists(StringConstants.DefaultGUIVirtualRootPathConfigKey)) { throw new Exception(StringConstants.DefaultGUIVirtualRootPathKeyOrValueNotFoundExceptionMessage); } // Ensure the value of the defaultGUIVirtualRootPath matches the value of the VirtualRootPath of one of the GUIMaps string defaultGUIVirtualRootPath = PlugInAppSettings.Get <string>(StringConstants.DefaultGUIVirtualRootPathConfigKey); GUI defaultGUI; try { defaultGUI = ConfigurationData.GUIS.GUIs.Single(gUI => gUI.GUIMap.VirtualRootPath == defaultGUIVirtualRootPath); } catch { throw new Exception(StringConstants.DefaultGUIVirtualRootPathDoesNotMatchExactlyOneGUIVirtualRootPathExceptionMessage); } // Set the default redirect. If defaultGUIVirtualRootPath is null, ensure there is not a double // in the path appHost.Config.DefaultRedirectPath = String.Format(StringConstants.DefaultRedirectPathTemplate, defaultGUI.GUIMap.VirtualRootPath); // Blazor requires the delivery of static files ending in certain file suffixes. // SS disallows some 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"); // Blazor requires CORS support, enable the ServiceStack CORS feature appHost.Plugins.Add(new CorsFeature( allowedMethods: "GET, POST, PUT, DELETE, OPTIONS", allowedOrigins: "*", allowCredentials: true, allowedHeaders: "content-type, Authorization, Accept")); // create the PlugIn's data object GUIServicesData gUIServicesData = new GUIServicesData(PlugInAppSettings, ConfigurationData); // Pass the Plugin's data structure to the container so it will be available to every other module and services appHost.GetContainer().Register <GUIServicesData>(d => gUIServicesData); // ToDo: enable the mechanisms that monitors each plugin-specific data sensor, and start them running // ToDo: Need to figure out if / how a PlugIn can add a PlugIn to the parent AppHost, if it detects there is a dependency }
// Configure your AppHost with the necessary configuration and dependencies your App needs public override void Configure(Container container) { Plugins.Add(new SharpPagesFeature()); // enable server-side rendering, see: https://sharpscript.net/docs/sharp-pages // This is already done for you however in many cases you may want to add // your own custom items that will be a part of this cascading app settings provider MultiAppSettingsBuilder multiAppSettingsBuilder = new MultiAppSettingsBuilder(); multiAppSettingsBuilder .AddNetCore(_coreConfig); // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#default-configuration // You can add text files or your own dictionary of custom values if you want AppSettings = multiAppSettingsBuilder.Build(); JsConfig.TreatEnumAsInteger = true; SetConfig(new HostConfig { UseCamelCase = true, UseSameSiteCookies = true, AddRedirectParamsToQueryString = true, DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), HostingEnvironment.IsDevelopment()), }); // for our app we will use an inmemory database. This can be replaced with no // code changes for sql server, mysql or any of the ormlite providers Plugins.Add(new AutoQueryDataFeature() { MaxLimit = int.MaxValue }); Plugins.Add(new AdminFeature()); container.Register <IDbConnectionFactory>(c => new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider)); using (var db = container.Resolve <IDbConnectionFactory>().Open()) { db.CreateTableIfNotExists <PostLog>(); } GatewayRequestFilters.Add((req, dto) => { if (dto is PostRequest || dto is PostQueryRequest) { using (var db = Resolve <IDbConnectionFactory>().Open()) { using (var trans = db.OpenTransaction()) { db.Insert <PostLog>(new PostLog() { EntryDate = DateTime.UtcNow, Identifier = (dto is PostRequest) ? ((PostRequest)dto).Id : string.Empty, RequestType = dto.ToString(), FilterType = FilterType.GatewayFilter }); trans.Commit(); } } } }); GlobalRequestFilters.Add((req, res, dto) => { if (dto is PostRequest || dto is PostQueryRequest) { using (var db = Resolve <IDbConnectionFactory>().Open()) { using (var trans = db.OpenTransaction()) { db.Insert <PostLog>(new PostLog() { EntryDate = DateTime.UtcNow, Identifier = (dto is PostRequest) ? ((PostRequest)dto).Id : string.Empty, RequestType = dto.GetType().ToString(), FilterType = FilterType.RequestFilter }); trans.Commit(); } } } }); container.AddTransient <IServiceGatewayFactory>(() => new CustomServiceGatewayFactory()); }