diff --git a/.editorconfig b/.editorconfig index 108919f..92ed11e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -78,6 +78,17 @@ dotnet_naming_rule.parameters_locals_must_be_camel_case.symbols = parameters_loc dotnet_naming_rule.parameters_locals_must_be_camel_case.style = camel_case_style dotnet_naming_rule.parameters_locals_must_be_camel_case.severity = warning +# Name all private fields starting with underscore +dotnet_naming_rule.private_members_with_underscore.symbols = private_fields +dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore +dotnet_naming_rule.private_members_with_underscore.severity = suggestion + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +dotnet_naming_style.prefix_underscore.capitalization = camel_case +dotnet_naming_style.prefix_underscore.required_prefix = _ + [*.cs] csharp_preferred_modifier_order = public, private, protected, internal, static, extern, new, virtual, abstract, sealed, override, readonly, unsafe, volatile, async:suggestion diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ae9aa2a..b8a4a9a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ # The image should use the same version as the UnitTests are -image: mcr.microsoft.com/dotnet/sdk:6.0 +image: mcr.microsoft.com/dotnet/sdk:8.0 variables: TZ: Europe/Berlin diff --git a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj index 0d8d14a..e7d5277 100644 --- a/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj +++ b/AMWD.Common.AspNetCore/AMWD.Common.AspNetCore.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0;net8.0 10.0 asp/v[0-9]* diff --git a/AMWD.Common.AspNetCore/Attributes/BasicAuthenticationAttribute.cs b/AMWD.Common.AspNetCore/Attributes/BasicAuthenticationAttribute.cs index 1cbbebd..ee7271c 100644 --- a/AMWD.Common.AspNetCore/Attributes/BasicAuthenticationAttribute.cs +++ b/AMWD.Common.AspNetCore/Attributes/BasicAuthenticationAttribute.cs @@ -45,13 +45,13 @@ namespace Microsoft.AspNetCore.Authorization if (isAllowAnonymous) return; - if (!context.HttpContext.Request.Headers.ContainsKey("Authorization")) + if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var authHeaderValue)) { SetAuthenticateRequest(context); return; } - var authHeader = AuthenticationHeaderValue.Parse(context.HttpContext.Request.Headers["Authorization"]); + var authHeader = AuthenticationHeaderValue.Parse(authHeaderValue); byte[] decoded = Convert.FromBase64String(authHeader.Parameter); string plain = Encoding.UTF8.GetString(decoded); @@ -84,22 +84,22 @@ namespace Microsoft.AspNetCore.Authorization : validator.Realm : Realm; - context.HttpContext.Response.Headers["WWW-Authenticate"] = "Basic"; + context.HttpContext.Response.Headers.WWWAuthenticate = "Basic"; if (!string.IsNullOrWhiteSpace(realm)) - context.HttpContext.Response.Headers["WWW-Authenticate"] = $"Basic realm=\"{realm.Trim().Replace("\"", "")}\""; + context.HttpContext.Response.Headers.WWWAuthenticate = $"Basic realm=\"{realm.Trim().Replace("\"", "")}\""; context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Result = new StatusCodeResult(StatusCodes.Status401Unauthorized); } - private async Task TrySetHttpUser(AuthorizationFilterContext context) + private static async Task TrySetHttpUser(AuthorizationFilterContext context) { var logger = context.HttpContext.RequestServices.GetService>(); try { - if (context.HttpContext.Request.Headers.ContainsKey("Authorization")) + if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out var authHeaderValue)) { - var authHeader = AuthenticationHeaderValue.Parse(context.HttpContext.Request.Headers["Authorization"]); + var authHeader = AuthenticationHeaderValue.Parse(authHeaderValue); byte[] decoded = Convert.FromBase64String(authHeader.Parameter); string plain = Encoding.UTF8.GetString(decoded); diff --git a/AMWD.Common.AspNetCore/Attributes/GoogleReCaptchaAttribute.cs b/AMWD.Common.AspNetCore/Attributes/GoogleReCaptchaAttribute.cs index cc612b5..faf646a 100644 --- a/AMWD.Common.AspNetCore/Attributes/GoogleReCaptchaAttribute.cs +++ b/AMWD.Common.AspNetCore/Attributes/GoogleReCaptchaAttribute.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters private const string VerificationUrl = "https://www.google.com/recaptcha/api/siteverify"; - private string privateKey; + private string _privateKey; /// /// Executes the validattion in background. @@ -61,9 +61,9 @@ namespace Microsoft.AspNetCore.Mvc.Filters public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var configuration = context.HttpContext.RequestServices.GetService(); - privateKey = configuration?.GetValue("Google:ReCaptcha:PrivateKey"); + _privateKey = configuration?.GetValue("Google:ReCaptcha:PrivateKey"); - if (string.IsNullOrWhiteSpace(privateKey)) + if (string.IsNullOrWhiteSpace(_privateKey)) return; await DoValidation(context).ConfigureAwait(false); @@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters using var httpClient = new HttpClient(); var param = new Dictionary { - { "secret", privateKey }, + { "secret", _privateKey }, { "response", token } }; var response = await httpClient.PostAsync(VerificationUrl, new FormUrlEncodedContent(param)).ConfigureAwait(false); diff --git a/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs b/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs index 4441633..5db301a 100644 --- a/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs +++ b/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs @@ -1,9 +1,9 @@ using System.Linq; using System.Net; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; namespace Microsoft.AspNetCore.Mvc.Filters { diff --git a/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs b/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs index 36d3e33..3b4ba29 100644 --- a/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs +++ b/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs @@ -1,9 +1,9 @@ using System.Linq; using System.Net; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; namespace Microsoft.AspNetCore.Mvc.Filters { diff --git a/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs b/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs index df7cd78..108bfb1 100644 --- a/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs +++ b/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs @@ -2,6 +2,7 @@ using System.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; +using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; namespace Microsoft.AspNetCore.Builder { diff --git a/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs b/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs index 337a933..c341fca 100644 --- a/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs +++ b/AMWD.Common.AspNetCore/Extensions/HttpContextExtensions.cs @@ -12,7 +12,7 @@ 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 = new[] { "Cf-Connecting-Ip", // set by Cloudflare "X-Real-IP", // wide-spread alternative to X-Forwarded-For @@ -51,8 +51,8 @@ namespace Microsoft.AspNetCore.Http string forwardedForAddress = null; var headerNames = string.IsNullOrWhiteSpace(ipHeaderName) - ? defaultIpHeaderNames - : new[] { ipHeaderName }.Concat(defaultIpHeaderNames); + ? _defaultIpHeaderNames + : new[] { ipHeaderName }.Concat(_defaultIpHeaderNames); foreach (string headerName in headerNames) { if (!httpContext.Request.Headers.ContainsKey(headerName)) @@ -67,9 +67,15 @@ namespace Microsoft.AspNetCore.Http } if (!string.IsNullOrWhiteSpace(forwardedForAddress) && IPAddress.TryParse(forwardedForAddress, out var remoteAddress)) - return remoteAddress.IsIPv4MappedToIPv6 ? remoteAddress.MapToIPv4() : remoteAddress; + { + return remoteAddress.IsIPv4MappedToIPv6 + ? remoteAddress.MapToIPv4() + : remoteAddress; + } - return httpContext.Connection.RemoteIpAddress; + return httpContext.Connection.RemoteIpAddress.IsIPv4MappedToIPv6 + ? httpContext.Connection.RemoteIpAddress.MapToIPv4() + : httpContext.Connection.RemoteIpAddress; } /// diff --git a/AMWD.Common.AspNetCore/Extensions/ModelStateDictionaryExtensions.cs b/AMWD.Common.AspNetCore/Extensions/ModelStateDictionaryExtensions.cs index d539746..32ad11e 100644 --- a/AMWD.Common.AspNetCore/Extensions/ModelStateDictionaryExtensions.cs +++ b/AMWD.Common.AspNetCore/Extensions/ModelStateDictionaryExtensions.cs @@ -15,11 +15,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// The type of the model. /// The type of the property. /// The instance. - /// The model. Only used to infer the model type. + /// The model. Only used to infer the model type. /// The that specifies the property. /// The error message to add. /// No member expression provided. - public static void AddModelError(this ModelStateDictionary modelState, TModel model, Expression> keyExpression, string errorMessage) + public static void AddModelError(this ModelStateDictionary modelState, TModel _, Expression> keyExpression, string errorMessage) { if (modelState is null) throw new ArgumentNullException(nameof(modelState)); diff --git a/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs b/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs index b335dbc..515b572 100644 --- a/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs +++ b/AMWD.Common.AspNetCore/ModelBinders/InvariantFloatingPointModelBinder.cs @@ -12,9 +12,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public class InvariantFloatingPointModelBinder : IModelBinder { - private readonly NumberStyles supportedNumberStyles; - private readonly ILogger logger; - private readonly CultureInfo cultureInfo; + private readonly NumberStyles _supportedNumberStyles; + private readonly ILogger _logger; + private readonly CultureInfo _cultureInfo; /// /// Initializes a new instance of . @@ -24,10 +24,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// The . public InvariantFloatingPointModelBinder(NumberStyles supportedStyles, CultureInfo cultureInfo, ILoggerFactory loggerFactory) { - this.cultureInfo = cultureInfo ?? throw new ArgumentNullException(nameof(cultureInfo)); + _cultureInfo = cultureInfo ?? throw new ArgumentNullException(nameof(cultureInfo)); - supportedNumberStyles = supportedStyles; - logger = loggerFactory?.CreateLogger(); + _supportedNumberStyles = supportedStyles; + _logger = loggerFactory?.CreateLogger(); } /// @@ -36,15 +36,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); - logger?.AttemptingToBindModel(bindingContext); + _logger?.AttemptingToBindModel(bindingContext); string modelName = bindingContext.ModelName; var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); if (valueProviderResult == ValueProviderResult.None) { - logger?.FoundNoValueInRequest(bindingContext); + _logger?.FoundNoValueInRequest(bindingContext); // no entry - logger?.DoneAttemptingToBindModel(bindingContext); + _logger?.DoneAttemptingToBindModel(bindingContext); return Task.CompletedTask; } @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding try { string value = valueProviderResult.FirstValue; - var culture = cultureInfo ?? valueProviderResult.Culture; + var culture = _cultureInfo ?? valueProviderResult.Culture; object model; if (string.IsNullOrWhiteSpace(value)) @@ -66,15 +66,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding } else if (type == typeof(float)) { - model = float.Parse(value, supportedNumberStyles, culture); + model = float.Parse(value, _supportedNumberStyles, culture); } else if (type == typeof(double)) { - model = double.Parse(value, supportedNumberStyles, culture); + model = double.Parse(value, _supportedNumberStyles, culture); } else if (type == typeof(decimal)) { - model = decimal.Parse(value, supportedNumberStyles, culture); + model = decimal.Parse(value, _supportedNumberStyles, culture); } else { @@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding // Conversion failed. } - logger?.DoneAttemptingToBindModel(bindingContext); + _logger?.DoneAttemptingToBindModel(bindingContext); return Task.CompletedTask; } } diff --git a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs index 1f0ba5d..f6b90ab 100644 --- a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs +++ b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationHandler.cs @@ -19,24 +19,44 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public class BasicAuthenticationHandler : AuthenticationHandler { - private readonly ILogger logger; - private readonly IBasicAuthenticationValidator validator; + 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 authentication scheme options. - /// The logger factory. - /// The URL encoder. - /// The system clock. + /// The monitor for the options instance. + /// The . + /// The . + /// The . /// An basic autentication validator implementation. - public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory loggerFactory, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator) - : base(options, loggerFactory, encoder, clock) + public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator) + : base(options, logger, encoder, clock) { - logger = loggerFactory.CreateLogger(); - this.validator = validator; + _logger = logger.CreateLogger(); + _validator = validator; } +#endif + /// protected override async Task HandleAuthenticateAsync() { @@ -44,13 +64,13 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication if (endpoint?.Metadata?.GetMetadata() != null) return AuthenticateResult.NoResult(); - if (!Request.Headers.ContainsKey("Authorization")) + if (!Request.Headers.TryGetValue("Authorization", out var authHeaderValue)) return AuthenticateResult.Fail("Authorization header missing"); ClaimsPrincipal principal; try { - var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); + var authHeader = AuthenticationHeaderValue.Parse(authHeaderValue); string plain = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader.Parameter)); // See: https://www.rfc-editor.org/rfc/rfc2617, page 6 @@ -58,11 +78,11 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication string password = plain[(username.Length + 1)..]; var ipAddress = Context.GetRemoteIpAddress(); - principal = await validator.ValidateAsync(username, password, ipAddress, Context.RequestAborted).ConfigureAwait(false); + principal = await _validator.ValidateAsync(username, password, ipAddress, Context.RequestAborted).ConfigureAwait(false); } catch (Exception ex) { - logger.LogError(ex, $"Handling the Basic Authentication failed: {ex.Message}"); + _logger.LogError(ex, $"Handling the Basic Authentication failed: {ex.Message}"); return AuthenticateResult.Fail("Authorization header invalid"); } diff --git a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs index 2f015bc..9bde87a 100644 --- a/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs +++ b/AMWD.Common.AspNetCore/Security/BasicAuthentication/BasicAuthenticationMiddleware.cs @@ -13,8 +13,8 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication /// public class BasicAuthenticationMiddleware { - private readonly RequestDelegate next; - private readonly IBasicAuthenticationValidator validator; + private readonly RequestDelegate _next; + private readonly IBasicAuthenticationValidator _validator; /// /// Initializes a new instance of the class. @@ -23,8 +23,8 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication /// A basic authentication validator. public BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator) { - this.next = next; - this.validator = validator; + _next = next; + _validator = validator; } /// @@ -37,7 +37,7 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication { if (!httpContext.Request.Headers.ContainsKey("Authorization")) { - SetAuthenticateRequest(httpContext, validator.Realm); + SetAuthenticateRequest(httpContext, _validator.Realm); return; } @@ -51,14 +51,14 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication string username = plain.Split(':').First(); string password = plain[(username.Length + 1)..]; - var principal = await validator.ValidateAsync(username, password, httpContext.GetRemoteIpAddress(), httpContext.RequestAborted).ConfigureAwait(false); + var principal = await _validator.ValidateAsync(username, password, httpContext.GetRemoteIpAddress(), httpContext.RequestAborted).ConfigureAwait(false); if (principal == null) { - SetAuthenticateRequest(httpContext, validator.Realm); + SetAuthenticateRequest(httpContext, _validator.Realm); return; } - await next.Invoke(httpContext).ConfigureAwait(false); + await _next.Invoke(httpContext).ConfigureAwait(false); } catch (Exception ex) { diff --git a/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs b/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs index 641358a..8800f3f 100644 --- a/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs +++ b/AMWD.Common.AspNetCore/Security/PathProtection/ProtectedPathMiddleware.cs @@ -10,9 +10,9 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection /// public class ProtectedPathMiddleware { - private readonly RequestDelegate next; - private readonly PathString path; - private readonly string policyName; + private readonly RequestDelegate _next; + private readonly PathString _path; + private readonly string _policyName; /// /// Initializes a new instance of the class. @@ -21,9 +21,9 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection /// The options to configure the middleware. public ProtectedPathMiddleware(RequestDelegate next, ProtectedPathOptions options) { - this.next = next; - path = options.Path; - policyName = options.PolicyName; + _next = next; + _path = options.Path; + _policyName = options.PolicyName; } /// @@ -35,16 +35,16 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection /// An awaitable task. public async Task InvokeAsync(HttpContext httpContext, IAuthorizationService authorizationService) { - if (httpContext.Request.Path.StartsWithSegments(path)) + if (httpContext.Request.Path.StartsWithSegments(_path)) { - var result = await authorizationService.AuthorizeAsync(httpContext.User, null, policyName).ConfigureAwait(false); + var result = await authorizationService.AuthorizeAsync(httpContext.User, null, _policyName).ConfigureAwait(false); if (!result.Succeeded) { await httpContext.ChallengeAsync().ConfigureAwait(false); return; } } - await next.Invoke(httpContext).ConfigureAwait(false); + await _next.Invoke(httpContext).ConfigureAwait(false); } } } diff --git a/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs b/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs index ca65fab..8492cea 100644 --- a/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs +++ b/AMWD.Common.AspNetCore/TagHelpers/ConditionClassTagHelper.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers [HtmlAttributeName("class")] public string CssClass { get; set; } - private IDictionary classValues; + private IDictionary _classValues; /// /// Gets or sets a dictionary containing all conditional class names and a boolean condition @@ -32,11 +32,11 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers { get { - return classValues ??= new Dictionary(StringComparer.OrdinalIgnoreCase); + return _classValues ??= new Dictionary(StringComparer.OrdinalIgnoreCase); } set { - classValues = value; + _classValues = value; } } @@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers /// A stateful HTML element used to generate an HTML tag. public override void Process(TagHelperContext context, TagHelperOutput output) { - var items = classValues.Where(e => e.Value).Select(e => e.Key).ToList(); + var items = _classValues.Where(e => e.Value).Select(e => e.Key).ToList(); if (!string.IsNullOrEmpty(CssClass)) items.Insert(0, CssClass); diff --git a/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs b/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs index bec8ad0..c523a8d 100644 --- a/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs +++ b/AMWD.Common.AspNetCore/TagHelpers/IntegrityHashTagHelper.cs @@ -18,8 +18,8 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers [HtmlTargetElement("script")] public class IntegrityHashTagHelper : TagHelper { - private readonly IWebHostEnvironment env; - private readonly string hostUrl; + private readonly IWebHostEnvironment _env; + private readonly string _hostUrl; /// /// Initializes a new instance of the class. @@ -28,8 +28,8 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers /// The application configuration. public IntegrityHashTagHelper(IWebHostEnvironment env, IConfiguration configuration) { - this.env = env; - hostUrl = configuration.GetValue("ASPNETCORE_APPL_URL", "http://localhost/"); + _env = env; + _hostUrl = configuration.GetValue("ASPNETCORE_APPL_URL", "http://localhost/"); } /// @@ -84,8 +84,8 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers { using var client = new HttpClient(); - if (!string.IsNullOrWhiteSpace(hostUrl)) - client.DefaultRequestHeaders.Referrer = new Uri(hostUrl); + if (!string.IsNullOrWhiteSpace(_hostUrl)) + client.DefaultRequestHeaders.Referrer = new Uri(_hostUrl); var response = await client.GetAsync(source).ConfigureAwait(false); fileBytes = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); @@ -103,12 +103,12 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers if (source.StartsWith("/")) source = source[1..]; - if (source.Contains("?")) + if (source.Contains('?')) source = source[..source.IndexOf("?")]; try { - string path = Path.Combine(env.WebRootPath, source); + string path = Path.Combine(_env.WebRootPath, source); fileBytes = await File.ReadAllBytesAsync(path).ConfigureAwait(false); } catch @@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers } string type; - byte[] hashBytes = new byte[0]; + byte[] hashBytes = Array.Empty(); switch (IntegrityStrength) { case 512: diff --git a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj index 68f4343..8409a10 100644 --- a/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj +++ b/AMWD.Common.EntityFrameworkCore/AMWD.Common.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0;net8.0 10.0 efc/v[0-9]* @@ -21,11 +21,18 @@ - - - + + + + + + + + + + diff --git a/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs b/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs index 5e41dde..6475393 100644 --- a/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs +++ b/AMWD.Common.EntityFrameworkCore/Exceptions/DatabaseProviderException.cs @@ -33,6 +33,8 @@ namespace System : base(message, innerException) { } +#if NET6_0 + /// /// Initializes a new instance of the class with serialized data. /// @@ -43,5 +45,7 @@ namespace System protected DatabaseProviderException(SerializationInfo info, StreamingContext context) : base(info, context) { } + +#endif } } diff --git a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs index f2eaec8..1e6f27c 100644 --- a/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs +++ b/AMWD.Common.EntityFrameworkCore/Extensions/DatabaseFacadeExtensions.cs @@ -24,6 +24,7 @@ namespace Microsoft.EntityFrameworkCore /// An action to set additional options. /// The cancellation token. /// true 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) { if (database == null) diff --git a/AMWD.Common.EntityFrameworkCore/Extensions/ModelConfigurationBuilderExtensions.cs b/AMWD.Common.EntityFrameworkCore/Extensions/ModelConfigurationBuilderExtensions.cs index 18289d2..b244536 100644 --- a/AMWD.Common.EntityFrameworkCore/Extensions/ModelConfigurationBuilderExtensions.cs +++ b/AMWD.Common.EntityFrameworkCore/Extensions/ModelConfigurationBuilderExtensions.cs @@ -10,14 +10,14 @@ namespace AMWD.Common.EntityFrameworkCore.Extensions public static class ModelConfigurationBuilderExtensions { /// - /// Adds converters for the and datatypes introduced with .NET 6.0. + /// Adds converters for the datatype introduced with .NET 6.0. /// /// /// As of 2022-06-04 only required for Microsoft SQL server on .NET 6.0. /// /// The instance. /// The instance after applying the converters. - public static ModelConfigurationBuilder AddDateOnlyTimeOnlyConverters(this ModelConfigurationBuilder builder) + public static ModelConfigurationBuilder AddDateOnlyConverters(this ModelConfigurationBuilder builder) { builder.Properties() .HaveConversion() @@ -26,6 +26,19 @@ namespace AMWD.Common.EntityFrameworkCore.Extensions .HaveConversion() .HaveColumnType("date"); + return builder; + } + + /// + /// Adds converters for the datatype introduced with .NET 6.0. + /// + /// + /// As of 2022-06-04 only required for Microsoft SQL server on .NET 6.0. + /// + /// The instance. + /// The instance after applying the converters. + public static ModelConfigurationBuilder AddTimeOnlyConverters(this ModelConfigurationBuilder builder) + { builder.Properties() .HaveConversion() .HaveColumnType("time"); diff --git a/AMWD.Common.EntityFrameworkCore/GlobalSuppressions.cs b/AMWD.Common.EntityFrameworkCore/GlobalSuppressions.cs new file mode 100644 index 0000000..3b7c57c --- /dev/null +++ b/AMWD.Common.EntityFrameworkCore/GlobalSuppressions.cs @@ -0,0 +1,3 @@ +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA2254")] diff --git a/AMWD.Common.Test/TcpClientMoq.cs b/AMWD.Common.Test/TcpClientMoq.cs index c736cd7..3962940 100644 --- a/AMWD.Common.Test/TcpClientMoq.cs +++ b/AMWD.Common.Test/TcpClientMoq.cs @@ -12,7 +12,7 @@ namespace AMWD.Common.Test /// public class TcpClientMoq { - private readonly Mock streamMock; + private readonly Mock _streamMock; /// /// Initializes a new instance of the class. @@ -22,8 +22,8 @@ namespace AMWD.Common.Test Callbacks = new(); Response = new byte[0]; - streamMock = new(); - streamMock + _streamMock = new(); + _streamMock .Setup(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((buffer, offset, count, _) => { @@ -39,7 +39,7 @@ namespace AMWD.Common.Test Callbacks.Add(callback); }) .Returns(Task.CompletedTask); - streamMock + _streamMock .Setup(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny())) .Callback((buffer, offset, count) => { @@ -55,7 +55,7 @@ namespace AMWD.Common.Test Callbacks.Add(callback); }); - streamMock + _streamMock .Setup(s => s.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback((buffer, offset, count, _) => { @@ -63,7 +63,7 @@ namespace AMWD.Common.Test Array.Copy(bytes, 0, buffer, offset, Math.Min(bytes.Length, count)); }) .ReturnsAsync(Response?.Length ?? 0); - streamMock + _streamMock .Setup(s => s.Read(It.IsAny(), It.IsAny(), It.IsAny())) .Callback((buffer, offset, count) => { @@ -75,7 +75,7 @@ namespace AMWD.Common.Test Mock = new(); Mock .Setup(c => c.GetStream()) - .Returns(streamMock.Object); + .Returns(_streamMock.Object); } /// @@ -107,28 +107,28 @@ namespace AMWD.Common.Test /// /// Number of calls. public void VerifyWriteAsync(Times times) - => streamMock.Verify(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); + => _streamMock.Verify(s => s.WriteAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); /// /// Verifies the number of calls writing synchronous to the stream. /// /// Number of calls. public void VerifyWriteSync(Times times) - => streamMock.Verify(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny()), times); + => _streamMock.Verify(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny()), times); /// /// Verifies the number of calls reading asynchronous from the stream. /// /// Number of calls. public void VerifyReadAsync(Times times) - => streamMock.Verify(s => s.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); + => _streamMock.Verify(s => s.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), times); /// /// Verifies the number of calls reading synchronous from the stream. /// /// Number of calls. public void VerifyReadSync(Times times) - => streamMock.Verify(s => s.Read(It.IsAny(), It.IsAny(), It.IsAny()), times); + => _streamMock.Verify(s => s.Read(It.IsAny(), It.IsAny(), It.IsAny()), times); /// /// Represents the placed TCP request. diff --git a/AMWD.Common/Cli/CommandLineParser.cs b/AMWD.Common/Cli/CommandLineParser.cs index 2936d2a..76e3537 100644 --- a/AMWD.Common/Cli/CommandLineParser.cs +++ b/AMWD.Common/Cli/CommandLineParser.cs @@ -12,9 +12,9 @@ namespace AMWD.Common.Cli { #region Private data - private string[] args; - private List parsedArguments; - private readonly List