diff --git a/src/WinSW.Core/Configuration/ServiceConfig.cs b/src/WinSW.Core/Configuration/ServiceConfig.cs index 33fbfe3..4ee0447 100644 --- a/src/WinSW.Core/Configuration/ServiceConfig.cs +++ b/src/WinSW.Core/Configuration/ServiceConfig.cs @@ -33,7 +33,7 @@ namespace WinSW.Configuration public virtual string? ServiceAccountUserName => null; - public virtual Native.SC_ACTION[] FailureActions => new Native.SC_ACTION[0]; + public virtual Native.SC_ACTION[] FailureActions => Array.Empty(); public virtual TimeSpan ResetFailureAfter => TimeSpan.FromDays(1); @@ -55,7 +55,7 @@ namespace WinSW.Configuration // Service management public virtual ServiceStartMode StartMode => ServiceStartMode.Automatic; - public virtual string[] ServiceDependencies => new string[0]; + public virtual string[] ServiceDependencies => Array.Empty(); public virtual bool Interactive => false; diff --git a/src/WinSW.Core/Configuration/XmlServiceConfig.cs b/src/WinSW.Core/Configuration/XmlServiceConfig.cs index d02375c..bd86039 100644 --- a/src/WinSW.Core/Configuration/XmlServiceConfig.cs +++ b/src/WinSW.Core/Configuration/XmlServiceConfig.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.ServiceProcess; using System.Text; @@ -96,6 +97,27 @@ namespace WinSW return new XmlServiceConfig(dom); } + private static int SingleIntElement(XmlNode parent, string tagName, int defaultValue) + { + XmlNode? e = parent.SelectSingleNode(tagName); + + return e is null ? defaultValue : int.Parse(e.InnerText, NumberFormatInfo.InvariantInfo); + } + + private static TimeSpan ParseTimeSpan(string v) + { + v = v.Trim(); + foreach (var s in Suffix) + { + if (v.EndsWith(s.Key)) + { + return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim(), NumberFormatInfo.InvariantInfo) * s.Value); + } + } + + return TimeSpan.FromMilliseconds(int.Parse(v, NumberFormatInfo.InvariantInfo)); + } + private string SingleElement(string tagName) { return this.SingleElement(tagName, false)!; @@ -119,31 +141,10 @@ namespace WinSW return e is null ? defaultValue : bool.Parse(e.InnerText); } - private int SingleIntElement(XmlNode parent, string tagName, int defaultValue) - { - XmlNode? e = parent.SelectSingleNode(tagName); - - return e is null ? defaultValue : int.Parse(e.InnerText); - } - private TimeSpan SingleTimeSpanElement(XmlNode parent, string tagName, TimeSpan defaultValue) { string? value = this.SingleElement(tagName, true); - return value is null ? defaultValue : this.ParseTimeSpan(value); - } - - private TimeSpan ParseTimeSpan(string v) - { - v = v.Trim(); - foreach (var s in Suffix) - { - if (v.EndsWith(s.Key)) - { - return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim()) * s.Value); - } - } - - return TimeSpan.FromMilliseconds(int.Parse(v)); + return value is null ? defaultValue : ParseTimeSpan(value); } private static readonly Dictionary Suffix = new Dictionary @@ -398,19 +399,19 @@ namespace WinSW } var pattern = patternNode.InnerText; - int period = this.SingleIntElement(e, "period", 1); + int period = SingleIntElement(e, "period", 1); return new TimeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, pattern, period); case "roll-by-size": - sizeThreshold = this.SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BytesPerKB; - int keepFiles = this.SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DefaultFilesToKeep); + sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BytesPerKB; + int keepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DefaultFilesToKeep); return new SizeBasedRollingLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern, sizeThreshold, keepFiles); case "append": return new DefaultLogAppender(this.LogDirectory, this.LogName, this.OutFileDisabled, this.ErrFileDisabled, this.OutFilePattern, this.ErrFilePattern); case "roll-by-size-time": - sizeThreshold = this.SingleIntElement(e, "sizeThreshold", 10 * 1024) * RollingSizeTimeLogAppender.BytesPerKB; + sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * RollingSizeTimeLogAppender.BytesPerKB; XmlNode? filePatternNode = e.SelectSingleNode("pattern"); if (filePatternNode is null) { @@ -527,7 +528,7 @@ namespace WinSW get { string? value = this.SingleElement("preshutdownTimeout", true); - return value is null ? default : this.ParseTimeSpan(value); + return value is null ? default : ParseTimeSpan(value); } } @@ -581,7 +582,7 @@ namespace WinSW XmlNodeList? childNodes = this.dom.SelectNodes("//onfailure"); if (childNodes is null) { - return new SC_ACTION[0]; + return Array.Empty(); } SC_ACTION[] result = new SC_ACTION[childNodes.Count]; @@ -597,7 +598,7 @@ namespace WinSW _ => throw new Exception("Invalid failure action: " + action) }; XmlAttribute? delay = node.Attributes["delay"]; - result[i] = new SC_ACTION(type, delay != null ? this.ParseTimeSpan(delay.Value) : TimeSpan.Zero); + result[i] = new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero); } return result; diff --git a/src/WinSW.Core/Download.cs b/src/WinSW.Core/Download.cs index 987531c..9faa9d7 100644 --- a/src/WinSW.Core/Download.cs +++ b/src/WinSW.Core/Download.cs @@ -106,7 +106,7 @@ namespace WinSW } // Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest - private void SetBasicAuthHeader(WebRequest request, string username, string password) + private static void SetBasicAuthHeader(WebRequest request, string username, string password) { string authInfo = username + ":" + password; authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo)); @@ -148,7 +148,7 @@ namespace WinSW break; case AuthType.Basic: - this.SetBasicAuthHeader(request, this.Username!, this.Password!); + SetBasicAuthHeader(request, this.Username!, this.Password!); break; default: @@ -166,7 +166,7 @@ namespace WinSW string tmpFilePath = this.To + ".tmp"; try { - using (WebResponse response = await request.GetResponseAsync()) + using (WebResponse response = await request.GetResponseAsync().ConfigureAwait(false)) using (Stream responseStream = response.GetResponseStream()) using (FileStream tmpStream = new FileStream(tmpFilePath, FileMode.Create)) { @@ -175,7 +175,7 @@ namespace WinSW lastModified = ((HttpWebResponse)response).LastModified; } - await responseStream.CopyToAsync(tmpStream); + await responseStream.CopyToAsync(tmpStream).ConfigureAwait(false); } FileHelper.MoveOrReplaceFile(this.To + ".tmp", this.To); diff --git a/src/WinSW.Core/Extensions/WinSWExtensionManager.cs b/src/WinSW.Core/Extensions/WinSWExtensionManager.cs index 1b629ea..b49768b 100644 --- a/src/WinSW.Core/Extensions/WinSWExtensionManager.cs +++ b/src/WinSW.Core/Extensions/WinSWExtensionManager.cs @@ -19,6 +19,33 @@ namespace WinSW.Extensions this.Extensions = new Dictionary(); } + private static IWinSWExtension CreateExtensionInstance(string id, string className) + { + object created; + + try + { + Type? t = Type.GetType(className); + if (t is null) + { + throw new ExtensionException(id, "Class " + className + " does not exist"); + } + + created = Activator.CreateInstance(t)!; + } + catch (Exception ex) + { + throw new ExtensionException(id, "Cannot load the class by name: " + className, ex); + } + + if (!(created is IWinSWExtension extension)) + { + throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType()); + } + + return extension; + } + /// /// Notifies all extensions that the wrapper is being started. /// They are supposed to run the initialization logic. @@ -137,7 +164,7 @@ namespace WinSW.Extensions var descriptor = WinSWExtensionDescriptor.FromXml(configNode); if (descriptor.Enabled) { - IWinSWExtension extension = this.CreateExtensionInstance(descriptor.Id, descriptor.ClassName); + IWinSWExtension extension = CreateExtensionInstance(descriptor.Id, descriptor.ClassName); extension.Descriptor = descriptor; try { @@ -146,7 +173,7 @@ namespace WinSW.Extensions catch (Exception ex) { // Consider any unexpected exception as fatal Log.Fatal("Failed to configure the extension " + id, ex); - throw ex; + throw; } this.Extensions.Add(id, extension); @@ -158,33 +185,6 @@ namespace WinSW.Extensions } } - private IWinSWExtension CreateExtensionInstance(string id, string className) - { - object created; - - try - { - Type? t = Type.GetType(className); - if (t is null) - { - throw new ExtensionException(id, "Class " + className + " does not exist"); - } - - created = Activator.CreateInstance(t)!; - } - catch (Exception ex) - { - throw new ExtensionException(id, "Cannot load the class by name: " + className, ex); - } - - if (!(created is IWinSWExtension extension)) - { - throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType()); - } - - return extension; - } - #endregion } } diff --git a/src/WinSW.Core/Util/XmlHelper.cs b/src/WinSW.Core/Util/XmlHelper.cs index 52a38bf..6417dae 100644 --- a/src/WinSW.Core/Util/XmlHelper.cs +++ b/src/WinSW.Core/Util/XmlHelper.cs @@ -5,7 +5,7 @@ using System.Xml; namespace WinSW.Util { - public class XmlHelper + public static class XmlHelper { /// /// Retrieves a single string element diff --git a/src/WinSW.Core/WinSWSystem.cs b/src/WinSW.Core/WinSWSystem.cs index bc3190f..2e3dc99 100644 --- a/src/WinSW.Core/WinSWSystem.cs +++ b/src/WinSW.Core/WinSWSystem.cs @@ -4,7 +4,7 @@ /// Class, which contains generic information about WinSW runtime. /// This information can be used by the service and extensions. /// - public class WinSWSystem + public static class WinSWSystem { /// /// Prefix for all environment variables being injected for WinSW