Skip to content

Commit

Permalink
Use C# 12 features (#1965)
Browse files Browse the repository at this point in the history
- Use primary constructors where relevant.
- Use collection literals where relevant.
- Apply various IDE suggestions.
- Use MSBuild items instead of assembly attributes.
  • Loading branch information
martincostello authored Sep 29, 2023
1 parent 06025cc commit 0a6829f
Show file tree
Hide file tree
Showing 65 changed files with 579 additions and 959 deletions.
11 changes: 0 additions & 11 deletions CommonAssemblyInfo.cs

This file was deleted.

8 changes: 7 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<Project>
<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)stylecop.json" Link="stylecop.json" />
<Compile Include="$(MSBuildThisFileDirectory)CommonAssemblyInfo.cs" />
<AssemblyAttribute Include="System.Reflection.AssemblyProduct">
<_Parameter1>London Travel</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.CLSCompliant">
<_Parameter1>false</_Parameter1>
<_Parameter1_IsLiteral>true</_Parameter1_IsLiteral>
</AssemblyAttribute>
</ItemGroup>
<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
Expand Down
1 change: 0 additions & 1 deletion LondonTravel.Site.sln
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.gitignore = .gitignore
.sonarrc = .sonarrc
build.ps1 = build.ps1
CommonAssemblyInfo.cs = CommonAssemblyInfo.cs
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
Expand Down
10 changes: 6 additions & 4 deletions src/LondonTravel.Site/ApiModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,31 +100,33 @@ public static IEndpointRouteBuilder MapApi(this IEndpointRouteBuilder app, ILogg

private static ErrorResponse Unauthorized(HttpContext httpContext, string message, string? detail = null)
{
#pragma warning disable SA1010
return new ErrorResponse()
{
Message = message ?? string.Empty,
RequestId = httpContext.TraceIdentifier,
StatusCode = StatusCodes.Status401Unauthorized,
Details = detail == null ? Array.Empty<string>() : new[] { detail },
Details = detail == null ? [] : [detail],
};
#pragma warning restore SA1010
}

[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
private static partial class Log
{
public static void AccessAuthorized(ILogger logger, string? userId, HttpContext httpContext)
{
AccessAuthorized(logger, userId, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers["User-Agent"]!);
AccessAuthorized(logger, userId, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers.UserAgent!);
}

public static void AccessDeniedNoAuthorization(ILogger logger, HttpContext httpContext)
{
AccessDeniedNoAuthorization(logger, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers["User-Agent"]!);
AccessDeniedNoAuthorization(logger, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers.UserAgent!);
}

public static void AccessDeniedUnknownToken(ILogger logger, HttpContext httpContext)
{
AccessDeniedUnknownToken(logger, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers["User-Agent"]!);
AccessDeniedUnknownToken(logger, httpContext.Connection.RemoteIpAddress, httpContext.Request.Headers.UserAgent!);
}

[LoggerMessage(
Expand Down
17 changes: 6 additions & 11 deletions src/LondonTravel.Site/AzureEnvironmentSecretManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,16 @@ namespace MartinCostello.LondonTravel.Site;
/// A class representing an implementation of <see cref="KeyVaultSecretManager"/>
/// that selects keys based on the Azure environment name. This class cannot be inherited.
/// </summary>
internal sealed class AzureEnvironmentSecretManager : KeyVaultSecretManager
/// <remarks>
/// Initializes a new instance of the <see cref="AzureEnvironmentSecretManager"/> class.
/// </remarks>
/// <param name="azureEnvironment">The name of the Azure environment.</param>
internal sealed class AzureEnvironmentSecretManager(string azureEnvironment) : KeyVaultSecretManager
{
/// <summary>
/// The secret prefix to use for the environment.
/// </summary>
private readonly string _prefix;

/// <summary>
/// Initializes a new instance of the <see cref="AzureEnvironmentSecretManager"/> class.
/// </summary>
/// <param name="azureEnvironment">The name of the Azure environment.</param>
public AzureEnvironmentSecretManager(string azureEnvironment)
{
_prefix = $"LondonTravel-{azureEnvironment}-";
}
private readonly string _prefix = $"LondonTravel-{azureEnvironment}-";

/// <inheritdoc />
public override string GetKey(KeyVaultSecret secret)
Expand Down
77 changes: 30 additions & 47 deletions src/LondonTravel.Site/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,25 @@ namespace MartinCostello.LondonTravel.Site.Controllers;

[Authorize]
[Route("account", Name = SiteRoutes.Account)]
public partial class AccountController : Controller
public partial class AccountController(
UserManager<LondonTravelUser> userManager,
SignInManager<LondonTravelUser> signInManager,
ISiteTelemetry telemetry,
TimeProvider timeProvider,
SiteOptions siteOptions,
ILogger<AccountController> logger) : Controller
{
#pragma warning disable SA1010
/// <summary>
/// The names of the authentication schemes that are disallowed for
/// sign-in to link Alexa to an account. This field is read-only.
/// </summary>
private static readonly string[] AuthenticationSchemesDisabledForAlexa = { "apple", "github", "google" };

private readonly UserManager<LondonTravelUser> _userManager;
private readonly SignInManager<LondonTravelUser> _signInManager;
private readonly ISiteTelemetry _telemetry;
private readonly TimeProvider _timeProvider;
private readonly bool _isEnabled;
private readonly ILogger _logger;

public AccountController(
UserManager<LondonTravelUser> userManager,
SignInManager<LondonTravelUser> signInManager,
ISiteTelemetry telemetry,
TimeProvider timeProvider,
SiteOptions siteOptions,
ILogger<AccountController> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_telemetry = telemetry;
_timeProvider = timeProvider;
_logger = logger;
private static readonly string[] AuthenticationSchemesDisabledForAlexa = ["apple", "github", "google"];
#pragma warning restore SA1010

_isEnabled =
private readonly bool _isEnabled =
siteOptions?.Authentication?.IsEnabled == true &&
siteOptions?.Authentication.ExternalProviders?.Any((p) => p.Value?.IsEnabled == true) == true;
}

[AllowAnonymous]
[HttpGet]
Expand Down Expand Up @@ -96,13 +82,13 @@ public async Task<IActionResult> SignOutPost()
return NotFound();
}

string? userId = _userManager.GetUserId(User);
string? userId = userManager.GetUserId(User);

await _signInManager.SignOutAsync();
await signInManager.SignOutAsync();

Log.UserSignedOut(_logger, userId);
Log.UserSignedOut(logger, userId);

_telemetry.TrackSignOut(userId);
telemetry.TrackSignOut(userId);

return RedirectToPage(SiteRoutes.Home);
}
Expand All @@ -124,7 +110,7 @@ public IActionResult ExternalSignIn(string? provider, string? returnUrl = null)
}

string? redirectUrl = Url.RouteUrl(SiteRoutes.ExternalSignInCallback, new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);

string errorRedirectUrl = GetErrorRedirectUrl();
SiteContext.SetErrorRedirect(properties, errorRedirectUrl);
Expand All @@ -144,25 +130,25 @@ public async Task<IActionResult> ExternalSignInCallback(string? returnUrl = null

if (remoteError != null)
{
Log.RemoteSignInError(_logger, remoteError);
Log.RemoteSignInError(logger, remoteError);
return View(nameof(SignIn));
}

var info = await _signInManager.GetExternalLoginInfoAsync();
var info = await signInManager.GetExternalLoginInfoAsync();

if (info == null)
{
return RedirectToRoute(SiteRoutes.SignIn);
}

var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: true);
var result = await signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: true);

if (result.Succeeded)
{
string? userId = _userManager.GetUserId(info.Principal);
string? userId = userManager.GetUserId(info.Principal);

Log.UserSignedIn(_logger, userId, info.LoginProvider);
_telemetry.TrackSignIn(userId, info.LoginProvider);
Log.UserSignedIn(logger, userId, info.LoginProvider);
telemetry.TrackSignIn(userId, info.LoginProvider);

return RedirectToLocal(returnUrl);
}
Expand All @@ -188,15 +174,15 @@ public async Task<IActionResult> ExternalSignInCallback(string? returnUrl = null
return View("SignIn");
}

var identityResult = await _userManager.CreateAsync(user);
var identityResult = await userManager.CreateAsync(user);

if (identityResult.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: true);
await signInManager.SignInAsync(user, isPersistent: true);

Log.UserCreated(_logger, user.Id, info.LoginProvider);
Log.UserCreated(logger, user.Id, info.LoginProvider);

_telemetry.TrackAccountCreated(user.Id!, user.Email, info.LoginProvider);
telemetry.TrackAccountCreated(user.Id!, user.Email, info.LoginProvider);

if (returnUri != null && IsRedirectAlexaAuthorization(returnUri.ToString()))
{
Expand Down Expand Up @@ -257,7 +243,7 @@ private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
Log.IdentityError(_logger, error.Code, error.Description);
Log.IdentityError(logger, error.Code, error.Description);
ModelState.AddModelError(string.Empty, error.Description);
}
}
Expand Down Expand Up @@ -288,7 +274,7 @@ private IActionResult RedirectToLocal(string? returnUrl)

var user = new LondonTravelUser()
{
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
CreatedAt = timeProvider.GetUtcNow().UtcDateTime,
Email = email,
GivenName = givenName,
Surname = surname,
Expand All @@ -315,7 +301,7 @@ private string GetErrorRedirectUrl()

private bool IsReferrerPageOrRoute(string routeName)
{
return IsUrlPageOrRoute(HttpContext.Request.Headers["referer"], routeName);
return IsUrlPageOrRoute(HttpContext.Request.Headers.Referer, routeName);
}

private bool IsUrlPageOrRoute(string? url, string pageOrRouteName)
Expand All @@ -328,10 +314,7 @@ private bool IsUrlPageOrRoute(string? url, string pageOrRouteName)

string? targetUrl = Url.RouteUrl(pageOrRouteName);

if (targetUrl is null)
{
targetUrl = Url.Page(pageOrRouteName);
}
targetUrl ??= Url.Page(pageOrRouteName);

if (uri.IsAbsoluteUri)
{
Expand Down
Loading

0 comments on commit 0a6829f

Please sign in to comment.