1
0

Adding support for .NET 8.0 LTS, renaming private fields to start with underscore

This commit is contained in:
2023-12-29 01:58:40 +01:00
parent 8bd511a936
commit 99d3f7758a
59 changed files with 922 additions and 871 deletions

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<NrtTagMatch>asp/v[0-9]*</NrtTagMatch>

View File

@@ -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<ClaimsPrincipal> TrySetHttpUser(AuthorizationFilterContext context)
private static async Task<ClaimsPrincipal> TrySetHttpUser(AuthorizationFilterContext context)
{
var logger = context.HttpContext.RequestServices.GetService<ILogger<BasicAuthenticationAttribute>>();
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);

View File

@@ -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;
/// <summary>
/// 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<IConfiguration>();
privateKey = configuration?.GetValue<string>("Google:ReCaptcha:PrivateKey");
_privateKey = configuration?.GetValue<string>("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<string, string>
{
{ "secret", privateKey },
{ "secret", _privateKey },
{ "response", token }
};
var response = await httpClient.PostAsync(VerificationUrl, new FormUrlEncodedContent(param)).ConfigureAwait(false);

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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;
}
/// <summary>

View File

@@ -15,11 +15,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> instance.</param>
/// <param name="model">The model. Only used to infer the model type.</param>
/// <param name="_">The model. Only used to infer the model type.</param>
/// <param name="keyExpression">The <see cref="MemberExpression"/> that specifies the property.</param>
/// <param name="errorMessage">The error message to add.</param>
/// <exception cref="InvalidOperationException">No member expression provided.</exception>
public static void AddModelError<TModel, TProperty>(this ModelStateDictionary modelState, TModel model, Expression<Func<TModel, TProperty>> keyExpression, string errorMessage)
public static void AddModelError<TModel, TProperty>(this ModelStateDictionary modelState, TModel _, Expression<Func<TModel, TProperty>> keyExpression, string errorMessage)
{
if (modelState is null)
throw new ArgumentNullException(nameof(modelState));

View File

@@ -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;
/// <summary>
/// Initializes a new instance of <see cref="InvariantFloatingPointModelBinder"/>.
@@ -24,10 +24,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
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<InvariantFloatingPointModelBinder>();
_supportedNumberStyles = supportedStyles;
_logger = loggerFactory?.CreateLogger<InvariantFloatingPointModelBinder>();
}
/// <inheritdoc />
@@ -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;
}
}

View File

@@ -19,24 +19,44 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly ILogger logger;
private readonly IBasicAuthenticationValidator validator;
private readonly ILogger _logger;
private readonly IBasicAuthenticationValidator _validator;
#if NET8_0_OR_GREATER
/// <summary>
/// Initializes a new instance of the <see cref="BasicAuthenticationHandler"/> class.
/// </summary>
/// <param name="options">The monitor for the options instance.</param>
/// <param name="logger">The <see cref="ILoggerFactory"/>.</param>
/// <param name="encoder">The <see cref="UrlEncoder"/>.</param>
/// <param name="validator">An basic autentication validator implementation.</param>
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, IBasicAuthenticationValidator validator)
: base(options, logger, encoder)
{
_logger = logger.CreateLogger<BasicAuthenticationHandler>();
_validator = validator;
}
#endif
#if NET6_0
/// <summary>
/// Initializes a new instance of the <see cref="BasicAuthenticationHandler"/> class.
/// </summary>
/// <param name="options">The authentication scheme options.</param>
/// <param name="loggerFactory">The logger factory.</param>
/// <param name="encoder">The URL encoder.</param>
/// <param name="clock">The system clock.</param>
/// <param name="options" > The monitor for the options instance.</param>
/// <param name="logger">The <see cref="ILoggerFactory"/>.</param>
/// <param name="encoder">The <see cref="UrlEncoder"/>.</param>
/// <param name="clock">The <see cref="ISystemClock"/>.</param>
/// <param name="validator">An basic autentication validator implementation.</param>
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory loggerFactory, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator)
: base(options, loggerFactory, encoder, clock)
public BasicAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator)
: base(options, logger, encoder, clock)
{
logger = loggerFactory.CreateLogger<BasicAuthenticationHandler>();
this.validator = validator;
_logger = logger.CreateLogger<BasicAuthenticationHandler>();
_validator = validator;
}
#endif
/// <inheritdoc/>
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
@@ -44,13 +64,13 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != 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");
}

View File

@@ -13,8 +13,8 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication
/// </summary>
public class BasicAuthenticationMiddleware
{
private readonly RequestDelegate next;
private readonly IBasicAuthenticationValidator validator;
private readonly RequestDelegate _next;
private readonly IBasicAuthenticationValidator _validator;
/// <summary>
/// Initializes a new instance of the <see cref="BasicAuthenticationMiddleware"/> class.
@@ -23,8 +23,8 @@ namespace AMWD.Common.AspNetCore.Security.BasicAuthentication
/// <param name="validator">A basic authentication validator.</param>
public BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator)
{
this.next = next;
this.validator = validator;
_next = next;
_validator = validator;
}
/// <summary>
@@ -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)
{

View File

@@ -10,9 +10,9 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection
/// </summary>
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;
/// <summary>
/// Initializes a new instance of the <see cref="ProtectedPathExtensions"/> class.
@@ -21,9 +21,9 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection
/// <param name="options">The options to configure the middleware.</param>
public ProtectedPathMiddleware(RequestDelegate next, ProtectedPathOptions options)
{
this.next = next;
path = options.Path;
policyName = options.PolicyName;
_next = next;
_path = options.Path;
_policyName = options.PolicyName;
}
/// <summary>
@@ -35,16 +35,16 @@ namespace AMWD.Common.AspNetCore.Security.PathProtection
/// <returns>An awaitable task.</returns>
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);
}
}
}

View File

@@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
[HtmlAttributeName("class")]
public string CssClass { get; set; }
private IDictionary<string, bool> classValues;
private IDictionary<string, bool> _classValues;
/// <summary>
/// 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<string, bool>(StringComparer.OrdinalIgnoreCase);
return _classValues ??= new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
}
set
{
classValues = value;
_classValues = value;
}
}
@@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
/// <param name="output">A stateful HTML element used to generate an HTML tag.</param>
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);

View File

@@ -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;
/// <summary>
/// Initializes a new instance of the <see cref="IntegrityHashTagHelper"/> class.
@@ -28,8 +28,8 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
/// <param name="configuration">The application configuration.</param>
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/");
}
/// <summary>
@@ -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<byte>();
switch (IntegrityStrength)
{
case 512: