diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b8a4a9a..53b649e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,9 @@ build-debug: - mv ./AMWD.Common.AspNetCore/bin/Debug/*.nupkg ./artifacts/ - mv ./AMWD.Common.AspNetCore/bin/Debug/*.snupkg ./artifacts/ - mv ./AMWD.Common.EntityFrameworkCore/bin/Debug/*.nupkg ./artifacts/ - - mv ./AMWD.Common.EntityFrameworkCore/bin/Debug/*.snupkg ./artifacts/ + - mv ./AMWD.Common.EntityFrameworkCore/bin/Debug/*.snupkg ./artifacts/ + - mv ./AMWD.Common.MessagePack/bin/Debug/*.nupkg ./artifacts/ + - mv ./AMWD.Common.MessagePack/bin/Debug/*.snupkg ./artifacts/ - mv ./AMWD.Common.Test/bin/Debug/*.nupkg ./artifacts/ - mv ./AMWD.Common.Test/bin/Debug/*.snupkg ./artifacts/ artifacts: @@ -72,7 +74,9 @@ build-release: - mv ./AMWD.Common.AspNetCore/bin/Release/*.nupkg ./artifacts/ - mv ./AMWD.Common.AspNetCore/bin/Release/*.snupkg ./artifacts/ - mv ./AMWD.Common.EntityFrameworkCore/bin/Release/*.nupkg ./artifacts/ - - mv ./AMWD.Common.EntityFrameworkCore/bin/Release/*.snupkg ./artifacts/ + - mv ./AMWD.Common.EntityFrameworkCore/bin/Release/*.snupkg ./artifacts/ + - mv ./AMWD.Common.MessagePack/bin/Release/*.nupkg ./artifacts/ + - mv ./AMWD.Common.MessagePack/bin/Release/*.snupkg ./artifacts/ - mv ./AMWD.Common.Test/bin/Release/*.nupkg ./artifacts/ - mv ./AMWD.Common.Test/bin/Release/*.snupkg ./artifacts/ artifacts: @@ -136,6 +140,19 @@ deploy-entityframework: - if: $CI_COMMIT_TAG =~ /^efc\/v[0-9.]+/ script: - dotnet nuget push -k $BAGET_APIKEY -s https://nuget.am-wd.de/v3/index.json --skip-duplicate artifacts/AMWD.Common.EntityFrameworkCore.*.nupkg + +deploy-messagepack: + stage: deploy + dependencies: + - build-release + - test-release + tags: + - docker + - lnx + rules: + - if: $CI_COMMIT_TAG =~ /^msgpack\/v[0-9.]+/ + script: + - dotnet nuget push -k $BAGET_APIKEY -s https://nuget.am-wd.de/v3/index.json --skip-duplicate artifacts/AMWD.Common.MessagePack.*.nupkg deploy-test: stage: deploy diff --git a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj index e7d5277..7cece0b 100644 --- a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj +++ b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj @@ -2,7 +2,7 @@ net6.0;net8.0 - 10.0 + 12.0 asp/v[0-9]* AMWD.Common.AspNetCore diff --git a/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs b/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs index c341fca..b39bb3f 100644 --- a/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs +++ b/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs @@ -12,12 +12,12 @@ namespace Microsoft.AspNetCore.Http public static class HttpContextExtensions { // Search these additional headers for a remote client ip address. - private static readonly string[] _defaultIpHeaderNames = new[] - { + private static readonly string[] _defaultIpHeaderNames = + [ "Cf-Connecting-Ip", // set by Cloudflare "X-Real-IP", // wide-spread alternative to X-Forwarded-For "X-Forwarded-For", // commonly used on all known proxies - }; + ]; /// /// Retrieves the antiforgery token. diff --git a/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs b/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs index 515b572..812b39f 100644 --- a/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs +++ b/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs @@ -9,26 +9,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// /// Custom floating point ModelBinder as the team of Microsoft is not capable of fixing their issue with other cultures than en-US. /// + /// + /// Initializes a new instance of . + /// + /// The . + /// The . + /// The . [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public class InvariantFloatingPointModelBinder : IModelBinder + public class InvariantFloatingPointModelBinder(NumberStyles supportedStyles, CultureInfo cultureInfo, ILoggerFactory loggerFactory) + : IModelBinder { - private readonly NumberStyles _supportedNumberStyles; - private readonly ILogger _logger; - private readonly CultureInfo _cultureInfo; - - /// - /// Initializes a new instance of . - /// - /// The . - /// The . - /// The . - public InvariantFloatingPointModelBinder(NumberStyles supportedStyles, CultureInfo cultureInfo, ILoggerFactory loggerFactory) - { - _cultureInfo = cultureInfo ?? throw new ArgumentNullException(nameof(cultureInfo)); - - _supportedNumberStyles = supportedStyles; - _logger = loggerFactory?.CreateLogger(); - } + private readonly NumberStyles _supportedNumberStyles = supportedStyles; + private readonly ILogger _logger = loggerFactory?.CreateLogger(); + private readonly CultureInfo _cultureInfo = cultureInfo ?? throw new ArgumentNullException(nameof(cultureInfo)); /// public Task BindModelAsync(ModelBindingContext bindingContext) diff --git a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs index f6b90ab..da20985 100644 --- a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs +++ b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs @@ -13,49 +13,39 @@ using Microsoft.Extensions.Options; namespace AMWD.Common.AspNetCore.Security.BasicAuthentication { +#if NET8_0_OR_GREATER /// /// Implements the for Basic Authentication. /// + /// + /// Initializes a new instance of the class. + /// + /// The monitor for the options instance. + /// The . + /// The . + /// An basic autentication validator implementation. [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public class BasicAuthenticationHandler : AuthenticationHandler + public class BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IBasicAuthenticationValidator validator) + : AuthenticationHandler(options, logger, encoder) +#else + /// + /// Implements the for Basic Authentication. + /// + /// + /// Initializes a new instance of the class. + /// + /// The monitor for the options instance. + /// The . + /// The . + /// The . + /// An basic autentication validator implementation. + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + public class BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator) + : AuthenticationHandler(options, logger, encoder, clock) +#endif { - private readonly ILogger _logger; - private readonly IBasicAuthenticationValidator _validator; - -#if NET8_0_OR_GREATER - /// - /// Initializes a new instance of the class. - /// - /// The monitor for the options instance. - /// The . - /// The . - /// An basic autentication validator implementation. - public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IBasicAuthenticationValidator validator) - : base(options, logger, encoder) - { - _logger = logger.CreateLogger(); - _validator = validator; - } -#endif - -#if NET6_0 - - /// - /// Initializes a new instance of the class. - /// - /// The monitor for the options instance. - /// The . - /// The . - /// The . - /// An basic autentication validator implementation. - public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator) - : base(options, logger, encoder, clock) - { - _logger = logger.CreateLogger(); - _validator = validator; - } - -#endif + private readonly ILogger _logger = logger.CreateLogger(); + private readonly IBasicAuthenticationValidator _validator = validator; /// protected override async Task HandleAuthenticateAsync() diff --git a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs index 9bde87a..ca7475d 100644 --- a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs +++ b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs @@ -11,21 +11,15 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication /// /// Implements a basic authentication. /// - public class BasicAuthenticationMiddleware + /// + /// Initializes a new instance of the class. + /// + /// The following delegate in the process chain. + /// A basic authentication validator. + public class BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator) { - private readonly RequestDelegate _next; - private readonly IBasicAuthenticationValidator _validator; - - /// - /// Initializes a new instance of the class. - /// - /// The following delegate in the process chain. - /// A basic authentication validator. - public BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator) - { - _next = next; - _validator = validator; - } + private readonly RequestDelegate _next = next; + private readonly IBasicAuthenticationValidator _validator = validator; /// /// The delegate invokation. @@ -35,15 +29,27 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication /// An awaitable task. public async Task InvokeAsync(HttpContext httpContext) { +#if NET8_0_OR_GREATER + if (!httpContext.Request.Headers.TryGetValue("Authorization", out var authHeaderValue)) + { + SetAuthenticateRequest(httpContext, _validator.Realm); + return; + } +#else if (!httpContext.Request.Headers.ContainsKey("Authorization")) { SetAuthenticateRequest(httpContext, _validator.Realm); return; } +#endif try { +#if NET8_0_OR_GREATER + var authHeader = AuthenticationHeaderValue.Parse(authHeaderValue); +#else var authHeader = AuthenticationHeaderValue.Parse(httpContext.Request.Headers["Authorization"]); +#endif byte[] decoded = Convert.FromBase64String(authHeader.Parameter); string plain = Encoding.UTF8.GetString(decoded); @@ -70,9 +76,9 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication private static void SetAuthenticateRequest(HttpContext httpContext, string realm) { - httpContext.Response.Headers["WWW-Authenticate"] = "Basic"; + httpContext.Response.Headers.WWWAuthenticate = "Basic"; if (!string.IsNullOrWhiteSpace(realm)) - httpContext.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{realm.Replace("\"", "")}\""; + httpContext.Response.Headers.WWWAuthenticate = $"Basic realm=\"{realm.Replace("\"", "")}\""; httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } diff --git a/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs b/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs index 8800f3f..41ab28d 100644 --- a/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs +++ b/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs @@ -8,23 +8,16 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection /// /// Implements a check to provide protected paths. /// - public class ProtectedPathMiddleware + /// + /// Initializes a new instance of the class. + /// + /// The following delegate in the process chain. + /// The options to configure the middleware. + public class ProtectedPathMiddleware(RequestDelegate next, ProtectedPathOptions options) { - private readonly RequestDelegate _next; - private readonly PathString _path; - private readonly string _policyName; - - /// - /// Initializes a new instance of the class. - /// - /// The following delegate in the process chain. - /// The options to configure the middleware. - public ProtectedPathMiddleware(RequestDelegate next, ProtectedPathOptions options) - { - _next = next; - _path = options.Path; - _policyName = options.PolicyName; - } + private readonly RequestDelegate _next = next; + private readonly PathString _path = options.Path; + private readonly string _policyName = options.PolicyName; /// /// The delegate invokation. diff --git a/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs b/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs index 8492cea..b19d552 100644 --- a/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs +++ b/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers if (items.Any()) { - string classes = string.Join(" ", items.ToArray()); + string classes = string.Join(" ", [.. items]); output.Attributes.Add("class", classes); } } diff --git a/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs b/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs index c523a8d..d0290f1 100644 --- a/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs +++ b/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs @@ -13,24 +13,19 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers /// /// A tag helper to dynamically create integrity checks for linked sources. /// + /// + /// Initializes a new instance of the class. + /// + /// The web host environment. + /// The application configuration. [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [HtmlTargetElement("link")] [HtmlTargetElement("script")] - public class IntegrityHashTagHelper : TagHelper + public class IntegrityHashTagHelper(IWebHostEnvironment env, IConfiguration configuration) + : TagHelper { - private readonly IWebHostEnvironment _env; - private readonly string _hostUrl; - - /// - /// Initializes a new instance of the class. - /// - /// The web host environment. - /// The application configuration. - public IntegrityHashTagHelper(IWebHostEnvironment env, IConfiguration configuration) - { - _env = env; - _hostUrl = configuration.GetValue("ASPNETCORE_APPL_URL", "http://localhost/"); - } + private readonly IWebHostEnvironment _env = env; + private readonly string _hostUrl = configuration.GetValue("ASPNETCORE_APPL_URL", "http://localhost/"); /// /// Gets or sets a value indicating whether the integrity should be calculated. @@ -118,7 +113,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers } string type; - byte[] hashBytes = Array.Empty(); + byte[] hashBytes = []; switch (IntegrityStrength) { case 512: diff --git a/AMWD.Common.AspNetCore/TagHelpers/NumberInputTagHelper.cs b/AMWD.Common.AspNetCore/TagHelpers/NumberInputTagHelper.cs index 10aad90..41ae538 100644 --- a/AMWD.Common.AspNetCore/TagHelpers/NumberInputTagHelper.cs +++ b/AMWD.Common.AspNetCore/TagHelpers/NumberInputTagHelper.cs @@ -9,17 +9,15 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// /// Adds additional behavior to the modelbinding for numeric properties. /// + /// + /// Initializes a new instance of the class. + /// + /// The HTML generator. [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [HtmlTargetElement("input", Attributes = "asp-for")] - public class NumberInputTagHelper : InputTagHelper + public class NumberInputTagHelper(IHtmlGenerator generator) + : InputTagHelper(generator) { - /// - /// Initializes a new instance of the class. - /// - /// The HTML generator. - public NumberInputTagHelper(IHtmlGenerator generator) - : base(generator) - { } /// public override void Process(TagHelperContext context, TagHelperOutput output) diff --git a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj index 8409a10..4d76a0a 100644 --- a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj +++ b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj @@ -2,7 +2,7 @@ net6.0;net8.0 - 10.0 + 12.0 efc/v[0-9]* AMWD.Common.EntityFrameworkCore @@ -22,17 +22,17 @@ - - + + - - + + - + diff --git a/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs b/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs index 6475393..18dbd7f 100644 --- a/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs +++ b/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs @@ -1,6 +1,4 @@ -using System.Runtime.Serialization; - -namespace System +namespace System { /// /// A DatabaseProvider specific exception. @@ -33,16 +31,16 @@ namespace System : base(message, innerException) { } -#if NET6_0 +#if !NET8_0_OR_GREATER /// /// Initializes a new instance of the class with serialized data. /// - /// The that holds the serialized object data about the exception being thrown. - /// The that contains contextual information about the source or destination. + /// The that holds the serialized object data about the exception being thrown. + /// The that contains contextual information about the source or destination. /// The info parameter is null. - /// The class name is null or is zero (0). - protected DatabaseProviderException(SerializationInfo info, StreamingContext context) + /// The class name is null or is zero (0). + protected DatabaseProviderException(Runtime.Serialization.SerializationInfo info, Runtime.Serialization.StreamingContext context) : base(info, context) { } diff --git a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs index 1e6f27c..dbcb0b2 100644 --- a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs +++ b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs @@ -15,7 +15,11 @@ namespace Microsoft.EntityFrameworkCore /// /// Extensions for the . /// +#if NET8_0_OR_GREATER + public static partial class DatabaseFacadeExtensions +#else public static class DatabaseFacadeExtensions +#endif { /// /// Applies migration files to the database. @@ -23,7 +27,7 @@ namespace Microsoft.EntityFrameworkCore /// The database connection. /// An action to set additional options. /// The cancellation token. - /// true on success, otherwise false or an exception is thrown. + /// on success, otherwise false or an exception is thrown. [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2208")] public static async Task ApplyMigrationsAsync(this DatabaseFacade database, Action optionsAction, CancellationToken cancellationToken = default) { @@ -211,20 +215,20 @@ END;" if (options.SourceAssembly == null) { availableMigrationFiles = Directory.GetFiles(options.Path) - .Where(f => f.ToLower().StartsWith(options.Path.ToLower())) - .Where(f => f.ToLower().EndsWith(".sql")) + .Where(f => f.StartsWith(options.Path, StringComparison.OrdinalIgnoreCase)) + .Where(f => f.EndsWith(".sql", StringComparison.OrdinalIgnoreCase)) .ToList(); } else { availableMigrationFiles = options.SourceAssembly .GetManifestResourceNames() - .Where(f => f.ToLower().StartsWith(options.Path.ToLower())) - .Where(f => f.ToLower().EndsWith(".sql")) + .Where(f => f.StartsWith(options.Path, StringComparison.OrdinalIgnoreCase)) + .Where(f => f.EndsWith(".sql", StringComparison.OrdinalIgnoreCase)) .ToList(); } - if (!availableMigrationFiles.Any()) + if (availableMigrationFiles.Count == 0) return true; using var command = connection.CreateCommand(); @@ -270,7 +274,11 @@ END;" { using var stream = options.SourceAssembly.GetManifestResourceStream(migrationFile); using var sr = new StreamReader(stream); +#if NET8_0_OR_GREATER + sqlScript = await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false); +#else sqlScript = await sr.ReadToEndAsync().ConfigureAwait(false); +#endif } if (string.IsNullOrWhiteSpace(sqlScript)) @@ -316,7 +324,11 @@ END;" { int affectedRows = 0; // Split script by a single slash in a line +#if NET8_0_OR_GREATER + string[] parts = FindSingleSlashInLine().Split(text); +#else string[] parts = Regex.Split(text, @"\r?\n[ \t]*/[ \t]*\r?\n"); +#endif foreach (string part in parts) { // Make writable copy @@ -325,7 +337,11 @@ END;" // Remove the trailing semicolon from commands where they're not supported // (Oracle doesn't like semicolons. To keep the semicolon, it must be directly // preceeded by "end".) - pt = Regex.Replace(pt.TrimEnd(), @"(?The with applied settings. public static DbContextOptionsBuilder UseDatabaseProvider(this DbContextOptionsBuilder optionsBuilder, IConfiguration configuration, Action optionsAction = null) { +#if NET8_0_OR_GREATER + ArgumentNullException.ThrowIfNull(optionsBuilder); + ArgumentNullException.ThrowIfNull(configuration); +#else if (optionsBuilder == null) throw new ArgumentNullException(nameof(optionsBuilder)); - if (configuration == null) throw new ArgumentNullException(nameof(configuration)); +#endif var options = new DatabaseProviderOptions(); optionsAction?.Invoke(options); diff --git a/AMWD.Common.MessagePack/AMWD.Common.MessagePack.csproj b/AMWD.Common.MessagePack/AMWD.Common.MessagePack.csproj new file mode 100644 index 0000000..986d0c6 --- /dev/null +++ b/AMWD.Common.MessagePack/AMWD.Common.MessagePack.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0;net6.0;net8.0 + 12.0 + + msgpack/v[0-9]* + AMWD.Common.MessagePack + AMWD.Common.MessagePack + + true + AMWD.Common.MessagePack + icon.png + README.md + + AM.WD Common Library for MessagePack + + + + + + + + + + + + + + + + diff --git a/AMWD.Common/Formatters/IPAddressArrayFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPAddressArrayFormatter.cs similarity index 92% rename from AMWD.Common/Formatters/IPAddressArrayFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPAddressArrayFormatter.cs index 6e9a119..0e40405 100644 --- a/AMWD.Common/Formatters/IPAddressArrayFormatter.cs +++ b/AMWD.Common.MessagePack/Formatters/IPAddressArrayFormatter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using AMWD.Common.Utilities; +using AMWD.Common.MessagePack.Utilities; namespace MessagePack.Formatters { @@ -66,7 +66,7 @@ namespace MessagePack.Formatters bytes.AddRange(buffer); } - options.Resolver.GetFormatterWithVerify().Serialize(ref writer, bytes.ToArray(), options); + options.Resolver.GetFormatterWithVerify().Serialize(ref writer, [.. bytes], options); } } } diff --git a/AMWD.Common/Formatters/IPAddressFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPAddressFormatter.cs similarity index 100% rename from AMWD.Common/Formatters/IPAddressFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPAddressFormatter.cs diff --git a/AMWD.Common/Formatters/IPAddressListFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPAddressListFormatter.cs similarity index 91% rename from AMWD.Common/Formatters/IPAddressListFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPAddressListFormatter.cs index 0a750bb..1a205b2 100644 --- a/AMWD.Common/Formatters/IPAddressListFormatter.cs +++ b/AMWD.Common.MessagePack/Formatters/IPAddressListFormatter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using AMWD.Common.Utilities; +using AMWD.Common.MessagePack.Utilities; namespace MessagePack.Formatters { @@ -61,7 +61,7 @@ namespace MessagePack.Formatters bytes.AddRange(buffer); } - options.Resolver.GetFormatterWithVerify().Serialize(ref writer, bytes.ToArray(), options); + options.Resolver.GetFormatterWithVerify().Serialize(ref writer, [.. bytes], options); } } } diff --git a/AMWD.Common/Formatters/IPNetworkArrayFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPNetworkArrayFormatter.cs similarity index 86% rename from AMWD.Common/Formatters/IPNetworkArrayFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPNetworkArrayFormatter.cs index 9866b1f..dfb8550 100644 --- a/AMWD.Common/Formatters/IPNetworkArrayFormatter.cs +++ b/AMWD.Common.MessagePack/Formatters/IPNetworkArrayFormatter.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; -using AMWD.Common.Utilities; -using MessagePack; -using MessagePack.Formatters; +using AMWD.Common.MessagePack.Utilities; +#if NET8_0_OR_GREATER +using IPNetwork = System.Net.IPNetwork; +#else using Microsoft.AspNetCore.HttpOverrides; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; +#endif -namespace AMWD.Common.Formatters +namespace MessagePack.Formatters { /// /// Serialization of an array to and from . diff --git a/AMWD.Common/Formatters/IPNetworkFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPNetworkFormatter.cs similarity index 82% rename from AMWD.Common/Formatters/IPNetworkFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPNetworkFormatter.cs index 9c408d9..a0aeffb 100644 --- a/AMWD.Common/Formatters/IPNetworkFormatter.cs +++ b/AMWD.Common.MessagePack/Formatters/IPNetworkFormatter.cs @@ -1,7 +1,12 @@ using System; using System.Linq; using System.Net; +#if NET8_0_OR_GREATER +using IPNetwork = System.Net.IPNetwork; +#else using Microsoft.AspNetCore.HttpOverrides; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; +#endif namespace MessagePack.Formatters { @@ -15,7 +20,7 @@ namespace MessagePack.Formatters public IPNetwork Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { if (reader.IsNil) - return null; + return default; byte[] bytes = options.Resolver.GetFormatterWithVerify().Deserialize(ref reader, options); return DeserializeInternal(bytes); @@ -24,7 +29,7 @@ namespace MessagePack.Formatters /// public void Serialize(ref MessagePackWriter writer, IPNetwork value, MessagePackSerializerOptions options) { - if (value == null) + if (value == default) { writer.WriteNil(); return; @@ -38,7 +43,11 @@ namespace MessagePack.Formatters { // IP network prefix has a maximum of 128 bit - therefore the length can be covered with a byte. byte prefixLength = (byte)network.PrefixLength; +#if NET8_0_OR_GREATER + byte[] prefixBytes = network.BaseAddress.GetAddressBytes(); +#else byte[] prefixBytes = network.Prefix.GetAddressBytes(); +#endif byte[] bytes = new byte[prefixBytes.Length + 1]; bytes[0] = prefixLength; diff --git a/AMWD.Common/Formatters/IPNetworkListFormatter.cs b/AMWD.Common.MessagePack/Formatters/IPNetworkListFormatter.cs similarity index 87% rename from AMWD.Common/Formatters/IPNetworkListFormatter.cs rename to AMWD.Common.MessagePack/Formatters/IPNetworkListFormatter.cs index 79b3499..7b0f53e 100644 --- a/AMWD.Common/Formatters/IPNetworkListFormatter.cs +++ b/AMWD.Common.MessagePack/Formatters/IPNetworkListFormatter.cs @@ -1,8 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using AMWD.Common.Utilities; +using AMWD.Common.MessagePack.Utilities; +#if NET8_0_OR_GREATER +using IPNetwork = System.Net.IPNetwork; +#else using Microsoft.AspNetCore.HttpOverrides; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; +#endif namespace MessagePack.Formatters { diff --git a/AMWD.Common.MessagePack/Utilities/NetworkHelper.cs b/AMWD.Common.MessagePack/Utilities/NetworkHelper.cs new file mode 100644 index 0000000..768adab --- /dev/null +++ b/AMWD.Common.MessagePack/Utilities/NetworkHelper.cs @@ -0,0 +1,17 @@ +using System; + +namespace AMWD.Common.MessagePack.Utilities +{ + /// + /// Provides some network utils. + /// + [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal static class NetworkHelper + { + public static void SwapBigEndian(byte[] array) + { + if (BitConverter.IsLittleEndian) + Array.Reverse(array); + } + } +} diff --git a/AMWD.Common.Test/AMWD.Common.Test.csproj b/AMWD.Common.Test/AMWD.Common.Test.csproj index f68fc70..fcb3652 100644 --- a/AMWD.Common.Test/AMWD.Common.Test.csproj +++ b/AMWD.Common.Test/AMWD.Common.Test.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 10.0 + 12.0 test/v[0-9]* AMWD.Common.Test @@ -22,7 +22,7 @@ - + diff --git a/AMWD.Common/AMWD.Common.csproj b/AMWD.Common/AMWD.Common.csproj index e2a49d9..d28ffb4 100644 --- a/AMWD.Common/AMWD.Common.csproj +++ b/AMWD.Common/AMWD.Common.csproj @@ -1,8 +1,8 @@  - netstandard2.0 - 10.0 + netstandard2.0;net8.0 + 12.0 AMWD.Common AMWD.Common @@ -21,10 +21,23 @@ - - + + + + + + + + + + + + <_Parameter1>UnitTests + + + diff --git a/AMWD.Common/Cli/CommandLineParser.cs b/AMWD.Common/Cli/CommandLineParser.cs index 76e3537..a7ceecd 100644 --- a/AMWD.Common/Cli/CommandLineParser.cs +++ b/AMWD.Common/Cli/CommandLineParser.cs @@ -14,7 +14,7 @@ namespace AMWD.Common.Cli private string[] _args; private List _parsedArguments; - private readonly List [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] - public class IPNetworkConverter : JsonConverter + public class IpNetworkConverter : JsonConverter { /// /// List of known types to use this converver. /// - public static readonly Type[] KnownTypes = new[] - { + public static readonly Type[] KnownTypes = + [ typeof(IPNetwork), typeof(IPNetwork[]), typeof(List), typeof(IEnumerable) - }; + ]; /// public override bool CanConvert(Type objectType) - { - return KnownTypes.Contains(objectType); - } + => KnownTypes.Contains(objectType); /// public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) @@ -40,7 +43,7 @@ namespace Newtonsoft.Json if (typeof(IPNetwork) == objectType) return Parse(str); - var networks = str.Split(';').Select(s => Parse(s)); + var networks = str.Split(';').Select(Parse); if (typeof(IPNetwork[]) == objectType) return networks.ToArray(); @@ -65,23 +68,27 @@ namespace Newtonsoft.Json str = ToString(net); if (value is IPNetwork[] netArray) - str = string.Join(";", netArray.Select(n => ToString(n))); + str = string.Join(";", netArray.Select(ToString)); if (value is List netList) - str = string.Join(";", netList.Select(n => ToString(n))); + str = string.Join(";", netList.Select(ToString)); if (value is IEnumerable netEnum) - str = string.Join(";", netEnum.Select(n => ToString(n))); + str = string.Join(";", netEnum.Select(ToString)); writer.WriteValue(str); } - private string ToString(IPNetwork net) + private static string ToString(IPNetwork net) { +#if NET8_0_OR_GREATER + return $"{net.BaseAddress}/{net.PrefixLength}"; +#else return $"{net.Prefix}/{net.PrefixLength}"; +#endif } - private IPNetwork Parse(string str) + private static IPNetwork Parse(string str) { string[] parts = str.Split('/'); var prefix = IPAddress.Parse(parts.First()); diff --git a/AMWD.Common/Extensions/DateTimeExtensions.cs b/AMWD.Common/Extensions/DateTimeExtensions.cs index 2da0626..becc9f1 100644 --- a/AMWD.Common/Extensions/DateTimeExtensions.cs +++ b/AMWD.Common/Extensions/DateTimeExtensions.cs @@ -1,7 +1,5 @@ using System.Text; -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")] - namespace System { /// diff --git a/AMWD.Common/Extensions/EnumExtensions.cs b/AMWD.Common/Extensions/EnumExtensions.cs index ee4d431..1a5cece 100644 --- a/AMWD.Common/Extensions/EnumExtensions.cs +++ b/AMWD.Common/Extensions/EnumExtensions.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.ComponentModel; -using System.ComponentModel.DataAnnotations; using System.Linq; namespace System @@ -41,13 +40,5 @@ namespace System /// The description or the string representation of the value. public static string GetDescription(this Enum value) => value.GetAttribute()?.Description ?? value.ToString(); - - /// - /// Returns the name from . - /// - /// The enum value. - /// The display name or the string representation of the value. - public static string GetDisplayName(this Enum value) - => value.GetAttribute()?.Name ?? value.ToString(); } } diff --git a/AMWD.Common/Extensions/ReaderWriterLockSlimExtensions.cs b/AMWD.Common/Extensions/ReaderWriterLockSlimExtensions.cs index eb644a0..3562252 100644 --- a/AMWD.Common/Extensions/ReaderWriterLockSlimExtensions.cs +++ b/AMWD.Common/Extensions/ReaderWriterLockSlimExtensions.cs @@ -56,16 +56,11 @@ return new DisposableReadWriteLock(rwLock, LockMode.Write); } - private struct DisposableReadWriteLock : IDisposable + private struct DisposableReadWriteLock(ReaderWriterLockSlim rwLock, LockMode lockMode) + : IDisposable { - private readonly ReaderWriterLockSlim _rwLock; - private LockMode _lockMode; - - public DisposableReadWriteLock(ReaderWriterLockSlim rwLock, LockMode lockMode) - { - _rwLock = rwLock; - _lockMode = lockMode; - } + private readonly ReaderWriterLockSlim _rwLock = rwLock; + private LockMode _lockMode = lockMode; public void Dispose() { diff --git a/AMWD.Common/Extensions/StreamExtensions.cs b/AMWD.Common/Extensions/StreamExtensions.cs index c56409e..481147b 100644 --- a/AMWD.Common/Extensions/StreamExtensions.cs +++ b/AMWD.Common/Extensions/StreamExtensions.cs @@ -40,7 +40,7 @@ namespace System.IO } while (ch != eol); - return encoding.GetString(bytes.ToArray()).Trim(); + return encoding.GetString([.. bytes]).Trim(); } /// @@ -73,7 +73,7 @@ namespace System.IO } while (ch != eol); - return encoding.GetString(bytes.ToArray()).Trim(); + return encoding.GetString([.. bytes]).Trim(); } } } diff --git a/AMWD.Common/Extensions/StringExtensions.cs b/AMWD.Common/Extensions/StringExtensions.cs index cb520b3..7a7e802 100644 --- a/AMWD.Common/Extensions/StringExtensions.cs +++ b/AMWD.Common/Extensions/StringExtensions.cs @@ -15,7 +15,12 @@ namespace System /// /// String extensions. /// +#if NET8_0_OR_GREATER + public static partial class StringExtensions +#else + public static class StringExtensions +#endif { /// /// Converts a hex string into a byte array. @@ -32,8 +37,13 @@ namespace System if (str.Length % 2 == 1) yield break; +#if NET8_0_OR_GREATER + if (InvalidHexCharRegex().IsMatch(str)) + yield break; +#else if (Regex.IsMatch(str, "[^0-9a-fA-F]")) yield break; +#endif for (int i = 0; i < str.Length; i += 2) yield return Convert.ToByte(str.Substring(i, 2), 16); @@ -179,14 +189,14 @@ namespace System { var dnsClientType = Type.GetType("DNS.Client.DnsClient, DNS") ?? throw new DllNotFoundException("The DNS NuGet package is required: https://www.nuget.org/packages/DNS/7.0.0"); var recordTypeType = Type.GetType("DNS.Protocol.RecordType, DNS"); - var resolveMethodInfo = dnsClientType.GetMethod("Resolve", new[] { typeof(string), recordTypeType, typeof(CancellationToken) }); + var resolveMethodInfo = dnsClientType.GetMethod("Resolve", [typeof(string), recordTypeType, typeof(CancellationToken)]); bool exists = false; foreach (var nameserver in nameservers) { - object dnsClient = Activator.CreateInstance(dnsClientType, new object[] { nameserver }); + object dnsClient = Activator.CreateInstance(dnsClientType, [nameserver]); - var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync(dnsClient, new object[] { mailAddress.Host, 15, CancellationToken.None })); // 15 = MX Record + var waitTask = Task.Run(async () => await resolveMethodInfo.InvokeAsync(dnsClient, [mailAddress.Host, 15, CancellationToken.None])); // 15 = MX Record waitTask.Wait(); object response = waitTask.Result; @@ -232,5 +242,10 @@ namespace System /// public static StringBuilder AppendLine(this StringBuilder sb, string value, string newLine) => sb.Append(value).Append(newLine); + +#if NET8_0_OR_GREATER + [GeneratedRegex("[^0-9a-fA-F]")] + private static partial Regex InvalidHexCharRegex(); +#endif } } diff --git a/AMWD.Common/Logging/FileLogger.cs b/AMWD.Common/Logging/FileLogger.cs index 11f3ae1..63c2452 100644 --- a/AMWD.Common/Logging/FileLogger.cs +++ b/AMWD.Common/Logging/FileLogger.cs @@ -6,8 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("UnitTests")] - namespace AMWD.Common.Logging { /// diff --git a/AMWD.Common/Packing/Ar/ArWriter.cs b/AMWD.Common/Packing/Ar/ArWriter.cs index c871079..fbb948f 100644 --- a/AMWD.Common/Packing/Ar/ArWriter.cs +++ b/AMWD.Common/Packing/Ar/ArWriter.cs @@ -8,7 +8,7 @@ namespace AMWD.Common.Packing.Ar /// Writes UNIX ar (archive) files in the GNU format. /// /// - /// Copied from + /// Copied from: DotnetMakeDeb /// public class ArWriter { diff --git a/AMWD.Common/Packing/Tar/TarReader.cs b/AMWD.Common/Packing/Tar/TarReader.cs index 90de862..51f891f 100644 --- a/AMWD.Common/Packing/Tar/TarReader.cs +++ b/AMWD.Common/Packing/Tar/TarReader.cs @@ -7,28 +7,24 @@ using AMWD.Common.Packing.Tar.Utils; namespace AMWD.Common.Packing.Tar { /// - /// Extract contents of a tar file represented by a stream for the TarReader constructor + /// Extract contents of a tar file represented by a stream for the TarReader constructor. /// /// - /// https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarReader.cs + /// Constructs TarReader object to read data from `tarredData` stream. + ///
+ /// Copied from: DotnetMakeDeb ///
- public class TarReader + /// A stream to read tar archive from + public class TarReader(Stream tarredData) { private readonly byte[] _dataBuffer = new byte[512]; - private readonly UsTarHeader _header; - private readonly Stream _inStream; + private readonly UsTarHeader _header = new(); + private readonly Stream _inStream = tarredData; private long _remainingBytesInFile; /// - /// Constructs TarReader object to read data from `tarredData` stream + /// Gets the file info (the header). /// - /// A stream to read tar archive from - public TarReader(Stream tarredData) - { - _inStream = tarredData; - _header = new UsTarHeader(); - } - public ITarHeader FileInfo => _header; /// @@ -66,7 +62,7 @@ namespace AMWD.Common.Packing.Tar } /// - /// Read data from a current file to a Stream. + /// Read data from the current archive to a Stream. /// /// A stream to read data to /// @@ -84,6 +80,11 @@ namespace AMWD.Common.Packing.Tar Debug.WriteLine("tar stream position Read out: " + _inStream.Position); } + /// + /// Reads data from the current archive to a buffer array. + /// + /// The buffer array. + /// The nuber of bytes read. protected int Read(out byte[] buffer) { if (_remainingBytesInFile == 0) diff --git a/AMWD.Common/Packing/Tar/TarWriter.cs b/AMWD.Common/Packing/Tar/TarWriter.cs index 77c8f7b..12f90f9 100644 --- a/AMWD.Common/Packing/Tar/TarWriter.cs +++ b/AMWD.Common/Packing/Tar/TarWriter.cs @@ -5,13 +5,32 @@ using AMWD.Common.Packing.Tar.Utils; namespace AMWD.Common.Packing.Tar { - // https://github.com/ygoe/DotnetMakeDeb/blob/v1.1.0/DotnetMakeDeb/Tar/TarWriter.cs + /// + /// Writes a tar (see GNU tar) archive to a stream. + /// + /// + /// Copied from: DotnetMakeDeb + /// public class TarWriter : LegacyTarWriter { + /// + /// Initilizes a new instance of the class. + /// + /// The stream to write the archive to. public TarWriter(Stream outStream) : base(outStream) { } + /// + /// Writes an entry header (file, dir, ...) to the archive. + /// + /// The name. + /// The last modification time. + /// The number of bytes. + /// The user id. + /// The group id. + /// The access mode. + /// The entry type. protected override void WriteHeader(string name, DateTime lastModificationTime, long count, int userId, int groupId, int mode, EntryType entryType) { var tarHeader = new UsTarHeader() @@ -29,6 +48,17 @@ namespace AMWD.Common.Packing.Tar OutStream.Write(tarHeader.GetHeaderValue(), 0, tarHeader.HeaderSize); } + /// + /// Writes an entry header (file, dir, ...) to the archive. + /// Hashes the username and groupname down to a HashCode. + /// + /// The name. + /// The last modification time. + /// The number of bytes. + /// The username. + /// The group name. + /// The access mode. + /// The entry type. protected virtual void WriteHeader(string name, DateTime lastModificationTime, long count, string userName, string groupName, int mode, EntryType entryType) { WriteHeader( @@ -41,6 +71,16 @@ namespace AMWD.Common.Packing.Tar entryType: entryType); } + /// + /// Writes a file to the archive. + /// + /// The file name. + /// The filesize in bytes. + /// The username. + /// The group name. + /// The access mode. + /// The last modification time. + /// The write handle. public virtual void Write(string name, long dataSizeInBytes, string userName, string groupName, int mode, DateTime lastModificationTime, WriteDataDelegate writeDelegate) { var writer = new DataWriter(OutStream, dataSizeInBytes); @@ -52,6 +92,16 @@ namespace AMWD.Common.Packing.Tar AlignTo512(dataSizeInBytes, false); } + /// + /// Writes a file to the archive. + /// + /// The file stream to add to the archive. + /// The filesize in bytes. + /// The file name. + /// The user id. + /// The group id. + /// The access mode. + /// The last modification time. public void Write(Stream data, long dataSizeInBytes, string fileName, string userId, string groupId, int mode, DateTime lastModificationTime) { diff --git a/AMWD.Common/Packing/Tar/Utils/LegacyTarWriter.cs b/AMWD.Common/Packing/Tar/Utils/LegacyTarWriter.cs index 82612d0..1944326 100644 --- a/AMWD.Common/Packing/Tar/Utils/LegacyTarWriter.cs +++ b/AMWD.Common/Packing/Tar/Utils/LegacyTarWriter.cs @@ -10,11 +10,14 @@ namespace AMWD.Common.Packing.Tar.Utils /// Implements a legacy TAR writer. /// /// - /// Copied from
+ /// Writes tar (see GNU tar) archive to a stream + ///
+ /// Copied from: DotnetMakeDeb /// - public class LegacyTarWriter : IDisposable + /// stream to write archive to + public class LegacyTarWriter(Stream outStream) : IDisposable { - private readonly Stream _outStream; + private readonly Stream _outStream = outStream; private bool _isClosed; /// @@ -22,15 +25,6 @@ namespace AMWD.Common.Packing.Tar.Utils /// protected byte[] buffer = new byte[1024]; - /// - /// Writes tar (see GNU tar) archive to a stream - /// - /// stream to write archive to - public LegacyTarWriter(Stream outStream) - { - _outStream = outStream; - } - /// /// Gets or sets a value indicating whether to read on zero. /// @@ -48,20 +42,25 @@ namespace AMWD.Common.Packing.Tar.Utils /// public void Dispose() - { - Close(); - } + => Close(); #endregion IDisposable Members + /// + /// Writes a directory entry. + /// + /// The path to the directory. + /// The user id. + /// The group id. + /// The access mode. + /// is not set. public void WriteDirectoryEntry(string path, int userId, int groupId, int mode) { if (string.IsNullOrEmpty(path)) - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path), "The path is not set."); if (path[path.Length - 1] != '/') - { path += '/'; - } + DateTime lastWriteTime; if (Directory.Exists(path)) { @@ -89,40 +88,50 @@ namespace AMWD.Common.Packing.Tar.Utils WriteHeader(path, lastWriteTime, 0, userId, groupId, mode, EntryType.Directory); } + /// + /// Writes a directory and its contents. + /// + /// The directory. + /// Write also sub-directories. + /// is not set. public void WriteDirectory(string directory, bool doRecursive) { if (string.IsNullOrEmpty(directory)) - throw new ArgumentNullException("directory"); + throw new ArgumentNullException(nameof(directory), "The directory is not set."); WriteDirectoryEntry(directory, 0, 0, 0755); string[] files = Directory.GetFiles(directory); foreach (string fileName in files) - { Write(fileName); - } string[] directories = Directory.GetDirectories(directory); foreach (string dirName in directories) { WriteDirectoryEntry(dirName, 0, 0, 0755); if (doRecursive) - { WriteDirectory(dirName, true); - } } } + /// + /// Writes a file. + /// + /// The file. + /// is not set. public void Write(string fileName) { if (string.IsNullOrEmpty(fileName)) - throw new ArgumentNullException("fileName"); - using (FileStream file = File.OpenRead(fileName)) - { - Write(file, file.Length, fileName, 61, 61, 511, File.GetLastWriteTime(file.Name)); - } + throw new ArgumentNullException(nameof(fileName), "The file name is not set."); + + using var fileStream = File.OpenRead(fileName); + Write(fileStream, fileStream.Length, fileName, 61, 61, 511, File.GetLastWriteTime(fileStream.Name)); } + /// + /// Writes a file stream. + /// + /// The file stream. public void Write(FileStream file) { string path = Path.GetFullPath(file.Name).Replace(Path.GetPathRoot(file.Name), string.Empty); @@ -130,22 +139,48 @@ namespace AMWD.Common.Packing.Tar.Utils Write(file, file.Length, path, 61, 61, 511, File.GetLastWriteTime(file.Name)); } + /// + /// Writes a stream. + /// + /// The contents. + /// The file size in bytes. + /// The file name. public void Write(Stream data, long dataSizeInBytes, string name) - { - Write(data, dataSizeInBytes, name, 61, 61, 511, DateTime.Now); - } + => Write(data, dataSizeInBytes, name, 61, 61, 511, DateTime.Now); + /// + /// Writes a file to the archive. + /// + /// The file name. + /// The file size in bytes. + /// The user id. + /// The group id. + /// The access mode. + /// The last modification timestamp. + /// The . public virtual void Write(string name, long dataSizeInBytes, int userId, int groupId, int mode, DateTime lastModificationTime, WriteDataDelegate writeDelegate) { - IArchiveDataWriter writer = new DataWriter(OutStream, dataSizeInBytes); + var writer = new DataWriter(OutStream, dataSizeInBytes); + WriteHeader(name, lastModificationTime, dataSizeInBytes, userId, groupId, mode, EntryType.File); + while (writer.CanWrite) - { writeDelegate(writer); - } + AlignTo512(dataSizeInBytes, false); } + /// + /// Writes a stream as file to the archive. + /// + /// The content as . + /// The file size in bytes. + /// The file name. + /// The user id. + /// The group id. + /// The access mode. + /// The last modification timestamp. + /// This writer is already closed. public virtual void Write(Stream data, long dataSizeInBytes, string name, int userId, int groupId, int mode, DateTime lastModificationTime) { if (_isClosed) @@ -189,21 +224,26 @@ namespace AMWD.Common.Packing.Tar.Utils Encoding.UTF8.GetBytes(name, 0, name.Length, entryName, 0); // add a "././@LongLink" pseudo-entry which contains the full name - using (var nameStream = new MemoryStream(entryName)) - { - WriteHeader("././@LongLink", lastModificationTime, entryName.Length, userId, groupId, mode, EntryType.LongName); - WriteContent(entryName.Length, nameStream); - AlignTo512(entryName.Length, false); - } + using var nameStream = new MemoryStream(entryName); + WriteHeader("././@LongLink", lastModificationTime, entryName.Length, userId, groupId, mode, EntryType.LongName); + WriteContent(entryName.Length, nameStream); + AlignTo512(entryName.Length, false); } + /// + /// Writes a stream as file to the archive. + /// + /// The size of the file in bytes. + /// The file content as stream. + /// has not enough to read from. protected void WriteContent(long count, Stream data) { while (count > 0 && count > buffer.Length) { int bytesRead = data.Read(buffer, 0, buffer.Length); if (bytesRead < 0) - throw new IOException("LegacyTarWriter unable to read from provided stream"); + throw new IOException($"{nameof(LegacyTarWriter)} unable to read from provided stream"); + if (bytesRead == 0) { if (ReadOnZero) @@ -218,7 +258,8 @@ namespace AMWD.Common.Packing.Tar.Utils { int bytesRead = data.Read(buffer, 0, (int)count); if (bytesRead < 0) - throw new IOException("LegacyTarWriter unable to read from provided stream"); + throw new IOException($"{nameof(LegacyTarWriter)} unable to read from provided stream"); + if (bytesRead == 0) { while (count > 0) @@ -232,6 +273,16 @@ namespace AMWD.Common.Packing.Tar.Utils } } + /// + /// Writes a entry header to the archive. + /// + /// The file name. + /// The last modification time. + /// The number of bytes. + /// The user id. + /// The group id. + /// The file mode. + /// The entry type protected virtual void WriteHeader(string name, DateTime lastModificationTime, long count, int userId, int groupId, int mode, EntryType entryType) { var header = new TarHeader @@ -247,6 +298,9 @@ namespace AMWD.Common.Packing.Tar.Utils OutStream.Write(header.GetHeaderValue(), 0, header.HeaderSize); } + /// + /// Aligns the entry to 512 bytes. + /// public void AlignTo512(long size, bool acceptZero) { size %= 512; @@ -258,6 +312,9 @@ namespace AMWD.Common.Packing.Tar.Utils } } + /// + /// Closes the writer and aligns to 512 bytes. + /// public virtual void Close() { if (_isClosed) diff --git a/AMWD.Common/Packing/Tar/Utils/TarException.cs b/AMWD.Common/Packing/Tar/Utils/TarException.cs index 34ef3f4..ed83e55 100644 --- a/AMWD.Common/Packing/Tar/Utils/TarException.cs +++ b/AMWD.Common/Packing/Tar/Utils/TarException.cs @@ -2,10 +2,51 @@ namespace AMWD.Common.Packing.Tar.Utils { + /// + /// Represents errors that occur during tar archive execution. + /// public class TarException : Exception { - public TarException(string message) : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + public TarException() + : base() + { } + + /// + /// Initializes a new instance of the class with a specified + /// error message. + /// + /// The message that describes the error. + public TarException(string message) + : base(message) + { } + + /// + /// Initializes a new instance of the System.Exception class with a specified error + /// message and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference + /// if no inner exception is specified. + public TarException(string message, Exception innerException) + : base(message, innerException) + { } + +#if !NET8_0_OR_GREATER + + /// + /// Initializes a new instance of the class with serialized data. + /// + /// The that holds the serialized + /// object data about the exception being thrown. + /// The that contains contextual information + /// about the source or destination. + protected TarException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) + : base(info, context) + { } + +#endif } } diff --git a/AMWD.Common/Utilities/AsyncQueue.cs b/AMWD.Common/Utilities/AsyncQueue.cs index a3e2ba9..9ad8c10 100644 --- a/AMWD.Common/Utilities/AsyncQueue.cs +++ b/AMWD.Common/Utilities/AsyncQueue.cs @@ -94,7 +94,7 @@ namespace System.Collections.Generic /// Determines whether an element is in the . /// /// The object to locate in the . The value can be null for reference types. - /// true if item is found in the ; otherwise, false. + /// if item is found in the , otherwise . [ExcludeFromCodeCoverage] public bool Contains(T item) { @@ -172,7 +172,7 @@ namespace System.Collections.Generic { lock (_queue) { - return _queue.ToArray(); + return [.. _queue]; } } @@ -304,7 +304,7 @@ namespace System.Collections.Generic /// Removes the object at the beginning of the , and copies it to the parameter. /// /// The removed object. - /// true if the object is successfully removed; false if the is empty. + /// if the object is successfully removed, if the is empty. public bool TryDequeue(out T result) { try @@ -325,7 +325,7 @@ namespace System.Collections.Generic /// parameter. The object is not removed from the . /// /// If present, the object at the beginning of the ; otherwise, the default value of . - /// true if there is an object at the beginning of the ; false if the is empty. + /// if there is an object at the beginning of the , if the is empty. public bool TryPeek(out T result) { try @@ -344,7 +344,7 @@ namespace System.Collections.Generic /// Removes the first occurrence of a specific object from the . /// /// The object to remove from the . The value can be null for reference types. - /// true if item is successfully removed; otherwise, false. This method also returns false if item was not found in the . + /// if item is successfully removed, otherwise . This method also returns if item was not found in the . public bool Remove(T item) { lock (_queue) diff --git a/AMWD.Common/Utilities/CryptographyHelper.cs b/AMWD.Common/Utilities/CryptographyHelper.cs index 1842f97..5967256 100644 --- a/AMWD.Common/Utilities/CryptographyHelper.cs +++ b/AMWD.Common/Utilities/CryptographyHelper.cs @@ -171,6 +171,7 @@ namespace System.Security.Cryptography #region Static methods #region Encryption +#pragma warning disable SYSLIB0041 #region AES @@ -185,7 +186,11 @@ namespace System.Security.Cryptography byte[] salt = new byte[_saltLength]; Array.Copy(cipher, salt, _saltLength); - using var gen = new Rfc2898DeriveBytes(password, salt); +#if NET8_0_OR_GREATER + using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1); +#else + using var gen = new Rfc2898DeriveBytes(password, salt, 1000); +#endif using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; @@ -225,7 +230,11 @@ namespace System.Security.Cryptography { byte[] salt = GetRandomBytes(_saltLength); - using var gen = new Rfc2898DeriveBytes(password, salt); +#if NET8_0_OR_GREATER + using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1); +#else + using var gen = new Rfc2898DeriveBytes(password, salt, 1000); +#endif using var aes = Aes.Create(); aes.Mode = CipherMode.CBC; @@ -271,7 +280,11 @@ namespace System.Security.Cryptography byte[] salt = new byte[_saltLength]; Array.Copy(cipher, salt, _saltLength); - using var gen = new Rfc2898DeriveBytes(password, salt); +#if NET8_0_OR_GREATER + using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1); +#else + using var gen = new Rfc2898DeriveBytes(password, salt, 1000); +#endif using var tdes = TripleDES.Create(); tdes.Mode = CipherMode.CBC; @@ -298,7 +311,11 @@ namespace System.Security.Cryptography { byte[] salt = GetRandomBytes(_saltLength); - using var gen = new Rfc2898DeriveBytes(password, salt); +#if NET8_0_OR_GREATER + using var gen = new Rfc2898DeriveBytes(password, salt, 1000, HashAlgorithmName.SHA1); +#else + using var gen = new Rfc2898DeriveBytes(password, salt, 1000); +#endif using var tdes = TripleDES.Create(); tdes.Mode = CipherMode.CBC; @@ -344,6 +361,7 @@ namespace System.Security.Cryptography #endregion Triple DES +#pragma warning restore SYSLIB0041 #endregion Encryption #region Hashing @@ -379,8 +397,12 @@ namespace System.Security.Cryptography /// The MD5 hash value, in hexadecimal notation. public static string Md5(byte[] bytes) { +#if NET8_0_OR_GREATER + return MD5.HashData(bytes).BytesToHex(); +#else using var md5 = MD5.Create(); return md5.ComputeHash(bytes).BytesToHex(); +#endif } #endregion MD5 @@ -416,8 +438,12 @@ namespace System.Security.Cryptography /// The SHA-1 hash value, in hexadecimal notation. public static string Sha1(byte[] bytes) { +#if NET8_0_OR_GREATER + return SHA1.HashData(bytes).BytesToHex(); +#else using var sha1 = SHA1.Create(); return sha1.ComputeHash(bytes).BytesToHex(); +#endif } #endregion SHA-1 @@ -453,8 +479,12 @@ namespace System.Security.Cryptography /// The SHA-256 hash value, in hexadecimal notation. public static string Sha256(byte[] bytes) { +#if NET8_0_OR_GREATER + return SHA256.HashData(bytes).BytesToHex(); +#else using var sha256 = SHA256.Create(); return sha256.ComputeHash(bytes).BytesToHex(); +#endif } #endregion SHA-256 @@ -490,8 +520,12 @@ namespace System.Security.Cryptography /// The SHA-512 hash value, in hexadecimal notation. public static string Sha512(byte[] bytes) { +#if NET8_0_OR_GREATER + return SHA512.HashData(bytes).BytesToHex(); +#else using var sha512 = SHA512.Create(); return sha512.ComputeHash(bytes).BytesToHex(); +#endif } #endregion SHA-512 diff --git a/AMWD.Common/Utilities/NetworkHelper.cs b/AMWD.Common/Utilities/NetworkHelper.cs index a71dc76..9faf02e 100644 --- a/AMWD.Common/Utilities/NetworkHelper.cs +++ b/AMWD.Common/Utilities/NetworkHelper.cs @@ -4,7 +4,12 @@ using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +#if NET8_0_OR_GREATER +using IPNetwork = System.Net.IPNetwork; +#else using Microsoft.AspNetCore.HttpOverrides; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; +#endif namespace AMWD.Common.Utilities { @@ -23,7 +28,7 @@ namespace AMWD.Common.Utilities public static List ResolveHost(string hostname, AddressFamily addressFamily = default) { if (string.IsNullOrWhiteSpace(hostname)) - return new(); + return []; if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) addressFamily = AddressFamily.Unspecified; @@ -31,7 +36,7 @@ namespace AMWD.Common.Utilities var ipAddress = ResolveIpAddress(hostname, addressFamily); // the name was an ip address, should not happen but experience tells other stories if (ipAddress != null) - return new() { ipAddress }; + return [ipAddress]; try { @@ -41,7 +46,7 @@ namespace AMWD.Common.Utilities } catch { - return new(); + return []; } } @@ -54,7 +59,7 @@ namespace AMWD.Common.Utilities public static List ResolveInterface(string interfaceName, AddressFamily addressFamily = default) { if (string.IsNullOrWhiteSpace(interfaceName)) - return new(); + return []; if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) addressFamily = AddressFamily.Unspecified; @@ -62,7 +67,7 @@ namespace AMWD.Common.Utilities var ipAddress = ResolveIpAddress(interfaceName, addressFamily); // the name was an ip address, should not happen but experience tells other stories if (ipAddress != null) - return new() { ipAddress }; + return [ipAddress]; try { @@ -74,45 +79,7 @@ namespace AMWD.Common.Utilities } catch { - return new(); - } - } - - /// - /// Parses a CIDR network definition. - /// - /// The network in CIDR. - /// The or null. - public static IPNetwork ParseNetwork(string network) - { - TryParseNetwork(network, out var ipNetwork); - return ipNetwork; - } - - /// - /// Tries to parse a CIDR network definition. - /// - /// The network in CIDR. - /// The parsed . - /// true on success, otherwise false. - public static bool TryParseNetwork(string network, out IPNetwork ipNetwork) - { - try - { - string[] parts = network.Split('/'); - if (parts.Length != 2) - throw new ArgumentException($"Invalid network type"); - - var prefix = IPAddress.Parse(parts.First()); - int prefixLength = int.Parse(parts.Last()); - - ipNetwork = new IPNetwork(prefix, prefixLength); - return true; - } - catch - { - ipNetwork = null; - return false; + return []; } } @@ -128,7 +95,11 @@ namespace AMWD.Common.Utilities { var list = new List(); +#if NET8_0_OR_GREATER + var ipAddress = network.BaseAddress; +#else var ipAddress = network.Prefix; +#endif while (network.Contains(ipAddress)) { list.Add(ipAddress); diff --git a/Common.sln b/Common.sln index f5bfa05..c1d89ff 100644 --- a/Common.sln +++ b/Common.sln @@ -41,6 +41,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{93EC8B16 nuget.config = nuget.config EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AMWD.Common.MessagePack", "AMWD.Common.MessagePack\AMWD.Common.MessagePack.csproj", "{EA014C15-93B6-4F2C-8229-1C13E22BF84A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {9469D87B-126E-4338-92E3-701F762CB54D}.Debug|Any CPU.Build.0 = Debug|Any CPU {9469D87B-126E-4338-92E3-701F762CB54D}.Release|Any CPU.ActiveCfg = Release|Any CPU {9469D87B-126E-4338-92E3-701F762CB54D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA014C15-93B6-4F2C-8229-1C13E22BF84A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA014C15-93B6-4F2C-8229-1C13E22BF84A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA014C15-93B6-4F2C-8229-1C13E22BF84A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA014C15-93B6-4F2C-8229-1C13E22BF84A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -80,6 +86,7 @@ Global {86DE1B7C-3ECF-49B1-AB28-A976A3973FF5} = {AFBF83AE-FE7D-48C1-B7E7-31BF3E17C6FB} {7196DA2B-D858-4B25-BC23-865175CFCDEC} = {AFBF83AE-FE7D-48C1-B7E7-31BF3E17C6FB} {93EC8B16-7DEF-4E39-B590-E804DEF7C607} = {AFBF83AE-FE7D-48C1-B7E7-31BF3E17C6FB} + {EA014C15-93B6-4F2C-8229-1C13E22BF84A} = {F2C7556A-99EB-43EB-8954-56A24AFE928F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {961E8DF8-DDF5-4D10-A510-CE409E9962AC} diff --git a/Directory.Build.props b/Directory.Build.props index 3d0cb4f..553ca7c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,6 @@ true false - false true true @@ -34,7 +33,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/UnitTests/AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddlewareTests.cs b/UnitTests/AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddlewareTests.cs index 9377d14..20ac3b5 100644 --- a/UnitTests/AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddlewareTests.cs +++ b/UnitTests/AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddlewareTests.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using AMWD.Common.AspNetCore.Security.BasicAuthentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -156,12 +157,16 @@ namespace UnitTests.AspNetCore.Security.BasicAuthentication var requestHeaderMock = new Mock(); foreach (var header in _requestHeaders) { + var strVal = new StringValues(header.Value); requestHeaderMock .Setup(h => h.ContainsKey(header.Key)) .Returns(true); requestHeaderMock .Setup(h => h[header.Key]) - .Returns(header.Value); + .Returns(strVal); + requestHeaderMock + .Setup(h => h.TryGetValue(header.Key, out strVal)) + .Returns(true); } var requestMock = new Mock(); @@ -174,6 +179,11 @@ namespace UnitTests.AspNetCore.Security.BasicAuthentication responseHeaderMock .SetupSet(h => h[It.IsAny()] = It.IsAny()) .Callback((key, value) => _responseHeadersCallback[key] = value); +#pragma warning disable CS0618 + responseHeaderMock + .SetupSet(h => h.WWWAuthenticate) + .Callback((value) => _responseHeadersCallback[HeaderNames.WWWAuthenticate] = value); +#pragma warning restore CS0618 var responseMock = new Mock(); responseMock diff --git a/UnitTests/Common/Extensions/EnumExtensionsTests.cs b/UnitTests/Common/Extensions/EnumExtensionsTests.cs index 7f0cd93..0099f7a 100644 --- a/UnitTests/Common/Extensions/EnumExtensionsTests.cs +++ b/UnitTests/Common/Extensions/EnumExtensionsTests.cs @@ -108,22 +108,6 @@ namespace UnitTests.Common.Extensions Assert.IsFalse(list.Any()); } - [TestMethod] - public void ShouldReturnDisplayNameOrStringRepresentation() - { - // arrange - var enumWithDisplayName = TestEnum.Two; - var enumWithoutDisplayName = TestEnum.Zero; - - // act - string displayName = enumWithDisplayName.GetDisplayName(); - string noDisplayName = enumWithoutDisplayName.GetDisplayName(); - - // assert - Assert.AreEqual("Zwei", displayName); - Assert.AreEqual(enumWithoutDisplayName.ToString(), noDisplayName); - } - internal enum TestEnum { [CustomMultiple("nix")] @@ -132,7 +116,6 @@ namespace UnitTests.Common.Extensions Zero, [Description("Eins")] One, - [Display(Name = "Zwei")] Two, } } diff --git a/UnitTests/Common/Packing/Ar/ArReaderTests.cs b/UnitTests/Common/Packing/Ar/ArReaderTests.cs index 688f54e..712a59a 100644 --- a/UnitTests/Common/Packing/Ar/ArReaderTests.cs +++ b/UnitTests/Common/Packing/Ar/ArReaderTests.cs @@ -12,16 +12,16 @@ namespace UnitTests.Common.Packing.Ar [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public class ArReaderTests { - private readonly DateTime fixedDateTime = new(2023, 03, 01, 10, 20, 30, 0, DateTimeKind.Utc); + private readonly DateTime _fixedDateTime = new(2023, 03, 01, 10, 20, 30, 0, DateTimeKind.Utc); - private Dictionary files; + private Dictionary _files; private Stream inStream; [TestInitialize] public void Initialize() { - files = new Dictionary + _files = new Dictionary { { "abcd.tmp", @@ -31,7 +31,7 @@ namespace UnitTests.Common.Packing.Ar FileSize = 14, GroupId = 456, Mode = 33188, - ModifyTime = fixedDateTime, + ModifyTime = _fixedDateTime, UserId = 123 } }, @@ -43,7 +43,7 @@ namespace UnitTests.Common.Packing.Ar FileSize = 14, GroupId = 456, Mode = 33188, - ModifyTime = fixedDateTime, + ModifyTime = _fixedDateTime, UserId = 123 } }, @@ -55,7 +55,7 @@ namespace UnitTests.Common.Packing.Ar FileSize = 13, GroupId = 456, Mode = 33188, - ModifyTime = fixedDateTime, + ModifyTime = _fixedDateTime, UserId = 123 } } @@ -64,7 +64,7 @@ namespace UnitTests.Common.Packing.Ar inStream = new MemoryStream(); inStream.Write(Encoding.ASCII.GetBytes("!\n")); - foreach (var file in files) + foreach (var file in _files) { int unixSeconds = (int)file.Value.ModifyTime.Subtract(DateTime.UnixEpoch).TotalSeconds; @@ -125,9 +125,9 @@ namespace UnitTests.Common.Packing.Ar // Assert Assert.IsNotNull(reader); - Assert.AreEqual(files.Count, fileList.Count); + Assert.AreEqual(_files.Count, fileList.Count); - foreach (string name in files.Keys) + foreach (string name in _files.Keys) Assert.IsTrue(fileList.Contains(name)); } @@ -139,14 +139,14 @@ namespace UnitTests.Common.Packing.Ar var reader = new ArReader(inStream); // Act - foreach (string name in files.Keys) + foreach (string name in _files.Keys) infos.Add(reader.GetFileInfo(name)); // Assert Assert.IsNotNull(reader); - Assert.AreEqual(files.Count, infos.Count); + Assert.AreEqual(_files.Count, infos.Count); - foreach (var expected in files.Values) + foreach (var expected in _files.Values) { var actual = infos.Single(fi => fi.FileName == expected.FileName); @@ -167,7 +167,7 @@ namespace UnitTests.Common.Packing.Ar var reader = new ArReader(inStream); // Act - foreach (string name in files.Keys) + foreach (string name in _files.Keys) { using var ms = new MemoryStream(); reader.ReadFile(name, ms); @@ -178,9 +178,9 @@ namespace UnitTests.Common.Packing.Ar // Assert Assert.IsNotNull(reader); - Assert.AreEqual(files.Count, contents.Count); + Assert.AreEqual(_files.Count, contents.Count); - foreach (var expected in files.Values) + foreach (var expected in _files.Values) { string content = contents[expected.FileName]; diff --git a/UnitTests/Common/Packing/Tar/TarReaderTests.cs b/UnitTests/Common/Packing/Tar/TarReaderTests.cs new file mode 100644 index 0000000..3e5abc7 --- /dev/null +++ b/UnitTests/Common/Packing/Tar/TarReaderTests.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTests.Common.Packing.Tar +{ + internal class TarReaderTests + { + } +} diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 6c1489a..aed5779 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -2,6 +2,7 @@ net8.0 + 12.0 false true false @@ -13,8 +14,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + +