public static ServiceStatus Deserialize(string file, ServiceConfig config) { Log.Trace("Trying to deserialize status XML file [{0}].", file); ServiceStatus status; var xs = new XmlSerializer(typeof(ServiceStatus)); try { var reader = File.OpenText(file); status = (ServiceStatus)xs.Deserialize(reader); reader.Close(); Log.Trace("Finished deserializing service status XML file."); } catch (Exception) { // if reading the status XML fails, we return an empty (new) one status = new ServiceStatus(); Log.Warn("Deserializing [{0}] failed, creating new status using defaults.", file); } status._config = config; ValidateStatus(status); // now set the storage filename: status._storageFile = file; return(status); }
/// <summary> /// Validate the configuration, throwing exceptions on invalid parameters. /// </summary> private static void ValidateConfiguration(ServiceConfig c) { Log.Debug("Validating configuration..."); var errmsg = ""; string CheckEmpty(string value, string name) { // if the string is null terminate the validation immediately since this means the // file doesn't contain a required parameter at all: if (value == null) { var msg = $"mandatory parameter missing: <{name}>"; Log.Error(msg); throw new ConfigurationErrorsException(msg); } if (string.IsNullOrWhiteSpace(value)) { return($"mandatory parameter unset: <{name}>\n"); } return(string.Empty); } string CheckMinValue(int value, string name, int min) { if (value == 0) { return($"<{name}> is unset (or set to 0), minimal accepted value is {min}\n"); } if (value < min) { return($"<{name}> must not be smaller than {min}\n"); } return(string.Empty); } string CheckLocalDrive(string value, string name) { var driveType = new DriveInfo(value).DriveType; if (driveType != DriveType.Fixed) { return($"<{name}> ({value}) must be a local fixed drive, not '{driveType}'!\n"); } return(string.Empty); } void WarnOnHighValue(int value, string name, int thresh) { if (value > thresh) { SubOptimal(value.ToString(), name, "value is set very high, please check!"); } } void SubOptimal(string value, string name, string message) { var msg = $">>> Sub-optimal setting detected: <{name}> [{value}] {message}"; ValidatorWarnings += msg + "\n"; Log.Warn(msg); } void LogAndThrow(string msg) { msg = $"Configuration issues detected:\n{msg}"; Log.Error(msg); throw new ConfigurationErrorsException(msg); } // check if all required parameters are there and non-empty / non-zero: errmsg += CheckEmpty(c.HostAlias, nameof(c.HostAlias)); errmsg += CheckEmpty(c.SourceDrive, nameof(c.SourceDrive)); errmsg += CheckEmpty(c.IncomingDirectory, nameof(c.IncomingDirectory)); errmsg += CheckEmpty(c.ManagedDirectory, nameof(c.ManagedDirectory)); errmsg += CheckEmpty(c.DestinationAlias, nameof(c.DestinationAlias)); errmsg += CheckEmpty(c.DestinationDirectory, nameof(c.DestinationDirectory)); errmsg += CheckEmpty(c.TmpTransferDir, nameof(c.TmpTransferDir)); errmsg += CheckMinValue(c.ServiceTimer, nameof(c.ServiceTimer), 1000); errmsg += CheckMinValue(c.MaxCpuUsage, nameof(c.MaxCpuUsage), 5); errmsg += CheckMinValue(c.MaxDiskQueue, nameof(c.MaxDiskQueue), 1); errmsg += CheckMinValue(c.MinAvailableMemory, nameof(c.MinAvailableMemory), 256); // if any of the required parameter checks failed we terminate now as many of the // string checks below would fail on empty strings: if (!string.IsNullOrWhiteSpace(errmsg)) { LogAndThrow(errmsg); } ////////// REQUIRED PARAMETERS SETTINGS VALIDATION ////////// // SourceDrive if (c.SourceDrive.Substring(1) != @":\") { errmsg += "<SourceDrive> must be of form [X:\\]\n!"; } errmsg += CheckLocalDrive(c.SourceDrive, nameof(c.SourceDrive)); // spooling directories: IncomingDirectory + ManagedDirectory if (c.IncomingDirectory.StartsWith(@"\")) { errmsg += "<IncomingDirectory> must not start with a backslash!\n"; } if (c.ManagedDirectory.StartsWith(@"\")) { errmsg += "<ManagedDirectory> must not start with a backslash!\n"; } // DestinationDirectory if (!Directory.Exists(c.DestinationDirectory)) { errmsg += $"can't find (or reach) destination: {c.DestinationDirectory}\n"; } // TmpTransferDir var tmpTransferPath = Path.Combine(c.DestinationDirectory, c.TmpTransferDir); if (!Directory.Exists(tmpTransferPath)) { errmsg += $"can't find (or reach) temporary transfer dir: {tmpTransferPath}\n"; } ////////// OPTIONAL PARAMETERS SETTINGS VALIDATION ////////// // EmailFrom if (!string.IsNullOrWhiteSpace(c.SmtpHost) && string.IsNullOrWhiteSpace(c.EmailFrom)) { errmsg += "<EmailFrom> must not be empty if <SmtpHost> is configured!\n"; } // DriveName foreach (var driveToCheck in c.SpaceMonitoring) { errmsg += CheckLocalDrive(driveToCheck.DriveName, nameof(driveToCheck.DriveName)); } ////////// WEAK CHECKS ON PARAMETERS SETTINGS ////////// // those checks are non-critical and are simply reported to the logs WarnOnHighValue(c.ServiceTimer, nameof(c.ServiceTimer), 10000); WarnOnHighValue(c.MaxCpuUsage, nameof(c.MaxCpuUsage), 75); WarnOnHighValue(c.MaxDiskQueue, nameof(c.MaxDiskQueue), 2000); WarnOnHighValue(c.MinAvailableMemory, nameof(c.MinAvailableMemory), 8192); WarnOnHighValue(c.AdminNotificationDelta, nameof(c.AdminNotificationDelta), 1440); WarnOnHighValue(c.GraceNotificationDelta, nameof(c.GraceNotificationDelta), 10080); WarnOnHighValue(c.StorageNotificationDelta, nameof(c.StorageNotificationDelta), 10080); WarnOnHighValue(c.GracePeriod, nameof(c.GracePeriod), 100); if (!c.DestinationDirectory.StartsWith(@"\\")) { SubOptimal(c.DestinationDirectory, "DestinationDirectory", "is not a UNC path!"); } // LogLevel var validLogLevels = new List <string> { "Warn", "Info", "Debug", "Trace" }; if (!validLogLevels.Contains(c.LogLevel)) { SubOptimal(c.LogLevel, "LogLevel", "is invalid, using 'Debug'. Valid options: " + string.Join(", ", validLogLevels)); c.LogLevel = "Debug"; } if (string.IsNullOrWhiteSpace(errmsg)) { return; } LogAndThrow(errmsg); }
/// <summary> /// Dummy method raising an exception (this class must not be serialized). /// </summary> public static void Serialize(string file, ServiceConfig c) { // the config is never meant to be written by us, therefore: throw new SettingsPropertyIsReadOnlyException("The config file must not be written by the service!"); }