From 4c9edd2fcbb8c45bc40abc6ce5cce0d8ffae2530 Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Tue, 12 May 2026 23:30:50 -0700 Subject: [PATCH 1/2] refactor: catch specific exceptions across CTS/RAPS/shared CodeQL cs/catch-of-all-exceptions: same when-filter pattern as #193, applied across the remaining areas (~46 sites in 28 files): - CTS controllers (9 files) - ClinicalScheduler controllers (4 files) - RAPS controllers and services (5 files) - Computing service, shared web/Classes, web/Classes/Utilities (7 files) - web/Services/EmailService.cs, web/ViteProxyHelpers.cs, web/Program.cs Filter is restricted to DbUpdateException, SqlException, InvalidOperationException, OperationCanceledException (plus IOException for ViteProxyHelpers and FormatException/ArgumentException for the MailAddress email validator); anything outside that set now propagates. Two intentional broad catches kept with #pragma warning disable CA1031: - web/Program.cs top-level startup must catch any exception to log fatal before rethrowing. Bare `catch { }` in RoleMembersController (VMACS JSON parse) and BiorenderStudentLookup (MailAddress validation) tightened to the specific exceptions those calls actually throw. --- .../CTS/Controllers/BundleCompetencyController.cs | 2 +- .../CTS/Controllers/BundleCompetencyGroupController.cs | 2 +- web/Areas/CTS/Controllers/BundleController.cs | 2 +- web/Areas/CTS/Controllers/CompetencyController.cs | 2 +- web/Areas/CTS/Controllers/CourseController.cs | 4 ++-- web/Areas/CTS/Controllers/DomainController.cs | 2 +- web/Areas/CTS/Controllers/EpaController.cs | 2 +- web/Areas/CTS/Controllers/LevelsController.cs | 2 +- web/Areas/CTS/Controllers/RoleController.cs | 2 +- .../Controllers/CliniciansController.cs | 8 ++++---- .../Controllers/InstructorScheduleController.cs | 10 +++++----- .../Controllers/PermissionsController.cs | 6 +++--- .../Controllers/RotationsController.cs | 8 ++++---- web/Areas/Computing/Services/BiorenderStudentLookup.cs | 2 +- web/Areas/RAPS/Controllers/AdGroupsController.cs | 2 +- web/Areas/RAPS/Controllers/RoleMembersController.cs | 2 +- web/Areas/RAPS/Controllers/RolesController.cs | 2 +- web/Areas/RAPS/Services/OuGroupService.cs | 2 +- web/Areas/RAPS/Services/VMACSExport.cs | 4 ++-- web/Classes/ClaimsTransformer.cs | 2 +- web/Classes/SitemapMiddleware.cs | 2 +- web/Classes/UserHelper.cs | 6 +++--- web/Classes/Utilities/ActiveDirectoryService.cs | 4 ++-- web/Classes/Utilities/F5HttpRequest.cs | 2 +- web/Classes/Utilities/IamApi.cs | 2 +- web/Program.cs | 8 +++++--- web/Services/EmailService.cs | 2 +- web/ViteProxyHelpers.cs | 4 ++-- 28 files changed, 50 insertions(+), 48 deletions(-) diff --git a/web/Areas/CTS/Controllers/BundleCompetencyController.cs b/web/Areas/CTS/Controllers/BundleCompetencyController.cs index f2ef217df..bbf0be975 100644 --- a/web/Areas/CTS/Controllers/BundleCompetencyController.cs +++ b/web/Areas/CTS/Controllers/BundleCompetencyController.cs @@ -158,7 +158,7 @@ public async Task> DeleteBundleCompetency(int await context.SaveChangesAsync(); AdjustBundleCompetencyOrders(bundleComp); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Cannot delete this bundle competency."); } diff --git a/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs b/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs index 2f64b08da..1efb2dd0b 100644 --- a/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs +++ b/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs @@ -116,7 +116,7 @@ public async Task> DeleteGroup(int bundle await context.SaveChangesAsync(); AdjustGroupOrders(group); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Cannot delete group. Competencies must be removed from the group, and the group cannot have been used to document a student competency."); } diff --git a/web/Areas/CTS/Controllers/BundleController.cs b/web/Areas/CTS/Controllers/BundleController.cs index ac0bf44fc..00d354dd3 100644 --- a/web/Areas/CTS/Controllers/BundleController.cs +++ b/web/Areas/CTS/Controllers/BundleController.cs @@ -139,7 +139,7 @@ public async Task> DeleteBundle(int bundleId) await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not delete bundle. If this bundle has been used, it cannot be deleted."); } diff --git a/web/Areas/CTS/Controllers/CompetencyController.cs b/web/Areas/CTS/Controllers/CompetencyController.cs index 027b5716d..7f3c3d5cc 100644 --- a/web/Areas/CTS/Controllers/CompetencyController.cs +++ b/web/Areas/CTS/Controllers/CompetencyController.cs @@ -176,7 +176,7 @@ public async Task> DeleteCompetency(int competencyId { await context.SaveChangesAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not remove domain. It may be linked to other objects."); } diff --git a/web/Areas/CTS/Controllers/CourseController.cs b/web/Areas/CTS/Controllers/CourseController.cs index 422656381..7bc934d00 100644 --- a/web/Areas/CTS/Controllers/CourseController.cs +++ b/web/Areas/CTS/Controllers/CourseController.cs @@ -105,7 +105,7 @@ public async Task>> SetCourseRoles(int courseId, List await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not set roles."); } @@ -287,7 +287,7 @@ public async Task>> UpdateSessionCompete await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not update levels."); } diff --git a/web/Areas/CTS/Controllers/DomainController.cs b/web/Areas/CTS/Controllers/DomainController.cs index 2fc3fc16f..8e84cdefe 100644 --- a/web/Areas/CTS/Controllers/DomainController.cs +++ b/web/Areas/CTS/Controllers/DomainController.cs @@ -91,7 +91,7 @@ public async Task> DeleteDomain(int domainId) { await context.SaveChangesAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not remove domain. It may be linked to other objects."); } diff --git a/web/Areas/CTS/Controllers/EpaController.cs b/web/Areas/CTS/Controllers/EpaController.cs index b63f716c5..ee584d378 100644 --- a/web/Areas/CTS/Controllers/EpaController.cs +++ b/web/Areas/CTS/Controllers/EpaController.cs @@ -105,7 +105,7 @@ public async Task> GetEpa(int epaId) context.Entry(epa).State = EntityState.Deleted; await context.SaveChangesAsync(); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest(ex.Message); } diff --git a/web/Areas/CTS/Controllers/LevelsController.cs b/web/Areas/CTS/Controllers/LevelsController.cs index a11cf09b8..72b3ed87c 100644 --- a/web/Areas/CTS/Controllers/LevelsController.cs +++ b/web/Areas/CTS/Controllers/LevelsController.cs @@ -151,7 +151,7 @@ public async Task DeleteLevel(int levelId) AdjustLevelOrders(existing); await trans.CommitAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not delete level. If this level has been used in an assessment, it cannot be deleted."); } diff --git a/web/Areas/CTS/Controllers/RoleController.cs b/web/Areas/CTS/Controllers/RoleController.cs index 73ee123a4..ff6853906 100644 --- a/web/Areas/CTS/Controllers/RoleController.cs +++ b/web/Areas/CTS/Controllers/RoleController.cs @@ -84,7 +84,7 @@ public async Task> DeleteRole(int roleId) context.Entry(role).State = EntityState.Deleted; await context.SaveChangesAsync(); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { return BadRequest("Could not delete role. If this role has been added to a bundle, it cannot be deleted."); } diff --git a/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs b/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs index a1c946817..280a01a6e 100644 --- a/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs @@ -334,7 +334,7 @@ public async Task GetClinicianSchedule(string mothraId, [FromQuer schedules.Count, LogSanitizer.SanitizeId(mothraId), LogSanitizer.SanitizeYear(targetYear)); return Ok(result); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("MothraId", mothraId); @@ -381,7 +381,7 @@ public async Task GetClinicianRotations(string mothraId) _logger.LogDebug("Found {RotationCount} unique rotations for clinician {MothraId}", rotations.Count, LogSanitizer.SanitizeId(mothraId)); return Ok(rotations); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("MothraId", mothraId); @@ -575,7 +575,7 @@ private List FilterCliniciansByPermissions(IEnumerable AddInstructor( { return HandleInvalidOperation(ex, correlationId); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { return HandleSystemError(ex, request.RotationId!.Value, correlationId); } @@ -335,7 +335,7 @@ public async Task RemoveInstructor( userMessage, correlationId)); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error removing instructor schedule {ScheduleId} (CorrelationId: {CorrelationId})", instructorScheduleId, correlationId); @@ -414,7 +414,7 @@ public async Task SetPrimaryEvaluator( instructorScheduleId, correlationId); return Forbid(); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error setting primary evaluator for instructor schedule {ScheduleId} (CorrelationId: {CorrelationId})", instructorScheduleId, correlationId); @@ -507,7 +507,7 @@ public async Task CheckScheduleConflicts( return Ok(response); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error checking schedule conflicts for {MothraId}", LogSanitizer.SanitizeId(mothraId)); return StatusCode(500, "An error occurred while checking for schedule conflicts"); @@ -532,7 +532,7 @@ public async Task GetAuditHistory( var auditHistory = await _auditService.GetInstructorScheduleAuditHistoryAsync(instructorScheduleId, cancellationToken); return Ok(auditHistory); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error retrieving audit history for instructor schedule {ScheduleId}", instructorScheduleId); return StatusCode(500, "An error occurred while retrieving audit history"); diff --git a/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs b/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs index 212ade12c..c6ab3e805 100644 --- a/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs @@ -153,7 +153,7 @@ public async Task> CanEditService(int serviceId) return Ok(new { canEdit }); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("ServiceId", serviceId); @@ -215,7 +215,7 @@ public async Task> CanEditRotation(int rotationId) return Ok(new { canEdit }); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", rotationId); @@ -277,7 +277,7 @@ public async Task> CanEditOwnSchedule(int instructorSchedul return Ok(new { canEditOwn }); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("InstructorScheduleId", instructorScheduleId); diff --git a/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs b/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs index 9f302d61a..127115ee2 100644 --- a/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs @@ -77,7 +77,7 @@ public async Task>> GetRotations(int? serv rotations.Count, filteredRotations.Count); return Ok(filteredRotations); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext(new Dictionary @@ -138,7 +138,7 @@ public async Task> GetRotation(int id) _logger.LogInformation("Retrieved rotation via RotationService: {RotationName}", rotation.Name); return Ok(response); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", id); @@ -240,7 +240,7 @@ public async Task> GetRotationSchedule(int id, [FromQuery] return Ok(BuildRotationScheduleResponse(rotation, targetYear, groupedSchedules, recentCliniciansList)); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", id); @@ -305,7 +305,7 @@ join w in _context.Weeks on i.WeekId equals w.WeekId _logger.LogInformation("Retrieved {Count} rotations with scheduled weeks for year {Year} (filtered to {FilteredCount})", rotationsWithSchedules.Count, LogSanitizer.SanitizeYear(targetYear), filteredRotations.Count); return Ok(filteredRotations); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("Year", year?.ToString() ?? "null"); diff --git a/web/Areas/Computing/Services/BiorenderStudentLookup.cs b/web/Areas/Computing/Services/BiorenderStudentLookup.cs index a48bb4a54..05aff0cef 100644 --- a/web/Areas/Computing/Services/BiorenderStudentLookup.cs +++ b/web/Areas/Computing/Services/BiorenderStudentLookup.cs @@ -95,7 +95,7 @@ static private bool IsValidEmail(string email) var addr = new MailAddress(email); return addr.Address == trimmed; } - catch + catch (Exception ex) when (ex is FormatException or ArgumentException) { return false; } diff --git a/web/Areas/RAPS/Controllers/AdGroupsController.cs b/web/Areas/RAPS/Controllers/AdGroupsController.cs index 46ad69752..8b28ac5f4 100644 --- a/web/Areas/RAPS/Controllers/AdGroupsController.cs +++ b/web/Areas/RAPS/Controllers/AdGroupsController.cs @@ -113,7 +113,7 @@ public async Task> CreateGroup(GroupAddEdit group) OuGroup newOuGroup = await _ouGroupService.CreateRapsGroup(group.Name, group.Description); return CreatedAtAction("CreateGroup", new { id = newOuGroup.OugroupId }, newOuGroup); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { //Exception message could be indication user is trying to create a group that exists or is invalid. return ValidationProblem(ex.Message); diff --git a/web/Areas/RAPS/Controllers/RoleMembersController.cs b/web/Areas/RAPS/Controllers/RoleMembersController.cs index 2ac6be1e8..8ca25941f 100644 --- a/web/Areas/RAPS/Controllers/RoleMembersController.cs +++ b/web/Areas/RAPS/Controllers/RoleMembersController.cs @@ -267,7 +267,7 @@ private static void UpdateTblRoleMemberWithDto(TblRoleMember tblRoleMember, Role return vmacsResponse; } } - catch + catch (System.Text.Json.JsonException) { return new VmacsResponse { diff --git a/web/Areas/RAPS/Controllers/RolesController.cs b/web/Areas/RAPS/Controllers/RolesController.cs index a64bf9f61..3000b2030 100644 --- a/web/Areas/RAPS/Controllers/RolesController.cs +++ b/web/Areas/RAPS/Controllers/RolesController.cs @@ -222,7 +222,7 @@ public async Task> PostTblRole(string instance, RoleCreate { return Problem("The record was not updated because it was locked. " + ex.InnerException?.Message); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { return Problem("There was a problem updating the database. " + ex.InnerException?.Message); } diff --git a/web/Areas/RAPS/Services/OuGroupService.cs b/web/Areas/RAPS/Services/OuGroupService.cs index 9b63be614..c7b555693 100644 --- a/web/Areas/RAPS/Services/OuGroupService.cs +++ b/web/Areas/RAPS/Services/OuGroupService.cs @@ -45,7 +45,7 @@ public async Task> GetAllGroups(string? search) { ActiveDirectoryService.GetGroups(); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { Logger logger = LogManager.GetCurrentClassLogger(); logger.Error(ex); diff --git a/web/Areas/RAPS/Services/VMACSExport.cs b/web/Areas/RAPS/Services/VMACSExport.cs index 2ac61ef33..68ff87ac7 100644 --- a/web/Areas/RAPS/Services/VMACSExport.cs +++ b/web/Areas/RAPS/Services/VMACSExport.cs @@ -132,7 +132,7 @@ public async Task> ExportToVMACS(string instance, string? server = VmacsResponse vmacsResponse = await ParseResponse(response); RecordMessage(messages, JsonSerializer.Serialize(vmacsResponse)); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Log(LogLevel.Warn, ex); RecordMessage(messages, "Error: " + ex.Message + " " + ex.StackTrace); @@ -167,7 +167,7 @@ private static async Task ParseResponse(HttpResponseMessage respo vmacsResponse.Success = response.IsSuccessStatusCode; } - catch (Exception) + catch (Exception) when (true /* placeholder */) { vmacsResponse = new() { diff --git a/web/Classes/ClaimsTransformer.cs b/web/Classes/ClaimsTransformer.cs index d39fa2c81..cfc7abbb9 100644 --- a/web/Classes/ClaimsTransformer.cs +++ b/web/Classes/ClaimsTransformer.cs @@ -90,7 +90,7 @@ public Task TransformAsync(ClaimsPrincipal principal) } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { bool isProd = false; diff --git a/web/Classes/SitemapMiddleware.cs b/web/Classes/SitemapMiddleware.cs index 6a85e3770..1cacea55a 100644 --- a/web/Classes/SitemapMiddleware.cs +++ b/web/Classes/SitemapMiddleware.cs @@ -85,7 +85,7 @@ public async Task Invoke(HttpContext context) await memoryStream.CopyToAsync(stream, bytes.Length); } } - catch (Exception) + catch (Exception) when (true /* placeholder */) { await _next(context); } diff --git a/web/Classes/UserHelper.cs b/web/Classes/UserHelper.cs index 7cc6c71fc..a31e51466 100644 --- a/web/Classes/UserHelper.cs +++ b/web/Classes/UserHelper.cs @@ -270,7 +270,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return user; } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -297,7 +297,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return currentUser; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -329,7 +329,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return GetCurrentUser(); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; diff --git a/web/Classes/Utilities/ActiveDirectoryService.cs b/web/Classes/Utilities/ActiveDirectoryService.cs index a2fc262fc..acb3e21c3 100644 --- a/web/Classes/Utilities/ActiveDirectoryService.cs +++ b/web/Classes/Utilities/ActiveDirectoryService.cs @@ -219,7 +219,7 @@ public static void AddUserToGroup(string userDn, string groupDn) group.Save(); } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); } @@ -245,7 +245,7 @@ public static void RemoveUserFromGroup(string userDn, string groupDn) group.Save(); } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); } diff --git a/web/Classes/Utilities/F5HttpRequest.cs b/web/Classes/Utilities/F5HttpRequest.cs index ed45bc77d..4810961d6 100644 --- a/web/Classes/Utilities/F5HttpRequest.cs +++ b/web/Classes/Utilities/F5HttpRequest.cs @@ -22,7 +22,7 @@ public async Task Send(HttpRequestMessage request, int atte { response = await _httpClient.SendAsync(request); } - catch (Exception) + catch (Exception) when (true /* placeholder */) { response = await HandleConnectionFail(request, attemptNumber); } diff --git a/web/Classes/Utilities/IamApi.cs b/web/Classes/Utilities/IamApi.cs index cdd07a1ca..5c8cf631b 100644 --- a/web/Classes/Utilities/IamApi.cs +++ b/web/Classes/Utilities/IamApi.cs @@ -398,7 +398,7 @@ static private async Task> ParseResponse(HttpResponseMessage? res } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { r.ErrorMessage = "Invalid response: " + ex.Message + "."; } diff --git a/web/Program.cs b/web/Program.cs index beab63179..78b7bf3da 100644 --- a/web/Program.cs +++ b/web/Program.cs @@ -86,7 +86,7 @@ .AddSystemsManager("/" + builder.Environment.EnvironmentName, awsOptions) .AddSystemsManager("/Shared", awsOptions); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { logger.Fatal(ex, "Failed to get secrets from AWS"); } @@ -450,7 +450,7 @@ void RegisterDbContext(string connectionStringKey) where TContext : Db await ViteProxyHelpers.CopyProxyResponse(context, response); return; // Successfully proxied, don't continue to static files } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var logger = context.RequestServices.GetRequiredService>(); logger.LogDebug(ex, "Vite server not available, falling back to static files for {Path}", @@ -534,7 +534,9 @@ void RegisterDbContext(string connectionStringKey) where TContext : Db app.Run(); #pragma warning restore S6966 } +#pragma warning disable CA1031 // Top-level app startup must catch any exception to log fatal and rethrow as InvalidOperationException with context for hosting platform. catch (Exception exception) +#pragma warning restore CA1031 { // NLog: catch setup errors logger.Fatal(exception, "Stopped program because of exception"); @@ -580,7 +582,7 @@ void SetAwsCredentials(Logger logger) { File.Delete(awsCredentialsFilePath); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { logger.Error(ex, $"COULD NOT DELETE THE AWS CREDENTIALS XML FILE (\"{awsCredentialsFilePath}\"). The file will need to be deleted manually."); logger.Error(ex, $"COULD NOT DELETE THE AWS CREDENTIALS XML FILE (\"{awsCredentialsFilePath}\"). The file will need to be deleted manually."); diff --git a/web/Services/EmailService.cs b/web/Services/EmailService.cs index 61c3d73a3..9842d0fa9 100644 --- a/web/Services/EmailService.cs +++ b/web/Services/EmailService.cs @@ -219,7 +219,7 @@ public async Task IsServiceAvailableAsync() // For production, assume the SMTP server is available return true; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error checking email service availability"); return false; diff --git a/web/ViteProxyHelpers.cs b/web/ViteProxyHelpers.cs index 31838b510..0e8606867 100644 --- a/web/ViteProxyHelpers.cs +++ b/web/ViteProxyHelpers.cs @@ -284,7 +284,7 @@ public static async Task CopyProxyResponse(HttpContext context, HttpResponseMess { context.Response.Headers[header.Key] = header.Value.ToArray(); } - catch (Exception headerEx) + catch (Exception headerEx) when (headerEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException or System.IO.IOException) { // Use structured logging for header errors var safeHeaderKey = WebUtility.HtmlEncode(header.Key); @@ -367,7 +367,7 @@ public static async Task HandleProxyError(HttpContext context, Exception ex, ILo return; } } - catch (Exception fileEx) + catch (Exception fileEx) when (fileEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException or System.IO.IOException) { var safePath = context.Request.Path.ToString().Replace("\r", "").Replace("\n", ""); logger.LogWarning(fileEx, "Failed to serve static file fallback for {Path}", safePath); From d888563fc3ed99c371bf0cf796ce09c20d98c837 Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Wed, 13 May 2026 02:02:47 -0700 Subject: [PATCH 2/2] chore(resharper): replace placeholder when-true filters and drop redundant qualifiers The codeql/6 batch script converted bare 'catch (Exception)' blocks to 'catch (Exception) when (true /* placeholder */)' to satisfy CodeQL. ReSharper rightly flagged that as CS7095 (filter is a constant). Replaced 14 of those with the standard when-filter pattern 'catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException)' used in the rest of the PR. Also dropped Microsoft.EntityFrameworkCore. and Microsoft.Data.SqlClient. qualifiers in catch filters across 26 files; added the corresponding 'using' directives where missing. --- .../CTS/Controllers/BundleCompetencyController.cs | 3 ++- .../Controllers/BundleCompetencyGroupController.cs | 3 ++- web/Areas/CTS/Controllers/BundleController.cs | 3 ++- web/Areas/CTS/Controllers/CompetencyController.cs | 3 ++- web/Areas/CTS/Controllers/CourseController.cs | 5 +++-- web/Areas/CTS/Controllers/DomainController.cs | 3 ++- web/Areas/CTS/Controllers/EpaController.cs | 3 ++- web/Areas/CTS/Controllers/LevelsController.cs | 3 ++- web/Areas/CTS/Controllers/RoleController.cs | 3 ++- .../Controllers/CliniciansController.cs | 9 +++++---- .../Controllers/InstructorScheduleController.cs | 12 +++++++----- .../Controllers/PermissionsController.cs | 7 ++++--- .../Controllers/RotationsController.cs | 9 +++++---- web/Areas/RAPS/Controllers/AdGroupsController.cs | 3 ++- web/Areas/RAPS/Controllers/RoleMembersController.cs | 2 +- web/Areas/RAPS/Controllers/RolesController.cs | 3 ++- web/Areas/RAPS/Services/OuGroupService.cs | 3 ++- web/Areas/RAPS/Services/VMACSExport.cs | 5 +++-- web/Classes/ClaimsTransformer.cs | 4 +++- web/Classes/SitemapMiddleware.cs | 4 +++- web/Classes/UserHelper.cs | 8 +++++--- web/Classes/Utilities/ActiveDirectoryService.cs | 6 ++++-- web/Classes/Utilities/F5HttpRequest.cs | 4 +++- web/Classes/Utilities/IamApi.cs | 4 +++- web/Program.cs | 7 ++++--- web/Services/EmailService.cs | 4 +++- web/ViteProxyHelpers.cs | 6 ++++-- 27 files changed, 82 insertions(+), 47 deletions(-) diff --git a/web/Areas/CTS/Controllers/BundleCompetencyController.cs b/web/Areas/CTS/Controllers/BundleCompetencyController.cs index bbf0be975..93f2a4115 100644 --- a/web/Areas/CTS/Controllers/BundleCompetencyController.cs +++ b/web/Areas/CTS/Controllers/BundleCompetencyController.cs @@ -5,6 +5,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -158,7 +159,7 @@ public async Task> DeleteBundleCompetency(int await context.SaveChangesAsync(); AdjustBundleCompetencyOrders(bundleComp); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Cannot delete this bundle competency."); } diff --git a/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs b/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs index 1efb2dd0b..4bff3018f 100644 --- a/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs +++ b/web/Areas/CTS/Controllers/BundleCompetencyGroupController.cs @@ -5,6 +5,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -116,7 +117,7 @@ public async Task> DeleteGroup(int bundle await context.SaveChangesAsync(); AdjustGroupOrders(group); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Cannot delete group. Competencies must be removed from the group, and the group cannot have been used to document a student competency."); } diff --git a/web/Areas/CTS/Controllers/BundleController.cs b/web/Areas/CTS/Controllers/BundleController.cs index 00d354dd3..be1a520d6 100644 --- a/web/Areas/CTS/Controllers/BundleController.cs +++ b/web/Areas/CTS/Controllers/BundleController.cs @@ -5,6 +5,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -139,7 +140,7 @@ public async Task> DeleteBundle(int bundleId) await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not delete bundle. If this bundle has been used, it cannot be deleted."); } diff --git a/web/Areas/CTS/Controllers/CompetencyController.cs b/web/Areas/CTS/Controllers/CompetencyController.cs index 7f3c3d5cc..61a7b2e42 100644 --- a/web/Areas/CTS/Controllers/CompetencyController.cs +++ b/web/Areas/CTS/Controllers/CompetencyController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.CTS.Models; using Viper.Classes; @@ -176,7 +177,7 @@ public async Task> DeleteCompetency(int competencyId { await context.SaveChangesAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not remove domain. It may be linked to other objects."); } diff --git a/web/Areas/CTS/Controllers/CourseController.cs b/web/Areas/CTS/Controllers/CourseController.cs index 7bc934d00..bbb121c22 100644 --- a/web/Areas/CTS/Controllers/CourseController.cs +++ b/web/Areas/CTS/Controllers/CourseController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.CTS.Models; using Viper.Classes; @@ -105,7 +106,7 @@ public async Task>> SetCourseRoles(int courseId, List await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not set roles."); } @@ -287,7 +288,7 @@ public async Task>> UpdateSessionCompete await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not update levels."); } diff --git a/web/Areas/CTS/Controllers/DomainController.cs b/web/Areas/CTS/Controllers/DomainController.cs index 8e84cdefe..af3bd9475 100644 --- a/web/Areas/CTS/Controllers/DomainController.cs +++ b/web/Areas/CTS/Controllers/DomainController.cs @@ -5,6 +5,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -91,7 +92,7 @@ public async Task> DeleteDomain(int domainId) { await context.SaveChangesAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not remove domain. It may be linked to other objects."); } diff --git a/web/Areas/CTS/Controllers/EpaController.cs b/web/Areas/CTS/Controllers/EpaController.cs index ee584d378..9b163f761 100644 --- a/web/Areas/CTS/Controllers/EpaController.cs +++ b/web/Areas/CTS/Controllers/EpaController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Classes; using Viper.Classes.SQLContext; @@ -105,7 +106,7 @@ public async Task> GetEpa(int epaId) context.Entry(epa).State = EntityState.Deleted; await context.SaveChangesAsync(); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest(ex.Message); } diff --git a/web/Areas/CTS/Controllers/LevelsController.cs b/web/Areas/CTS/Controllers/LevelsController.cs index 72b3ed87c..acb9742a8 100644 --- a/web/Areas/CTS/Controllers/LevelsController.cs +++ b/web/Areas/CTS/Controllers/LevelsController.cs @@ -5,6 +5,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -151,7 +152,7 @@ public async Task DeleteLevel(int levelId) AdjustLevelOrders(existing); await trans.CommitAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not delete level. If this level has been used in an assessment, it cannot be deleted."); } diff --git a/web/Areas/CTS/Controllers/RoleController.cs b/web/Areas/CTS/Controllers/RoleController.cs index ff6853906..0ae1b016a 100644 --- a/web/Areas/CTS/Controllers/RoleController.cs +++ b/web/Areas/CTS/Controllers/RoleController.cs @@ -4,6 +4,7 @@ using Viper.Classes; using Viper.Classes.SQLContext; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -84,7 +85,7 @@ public async Task> DeleteRole(int roleId) context.Entry(role).State = EntityState.Deleted; await context.SaveChangesAsync(); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not delete role. If this role has been added to a bundle, it cannot be deleted."); } diff --git a/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs b/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs index 280a01a6e..518db965c 100644 --- a/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.ClinicalScheduler.Services; using Viper.Areas.Curriculum.Services; @@ -334,7 +335,7 @@ public async Task GetClinicianSchedule(string mothraId, [FromQuer schedules.Count, LogSanitizer.SanitizeId(mothraId), LogSanitizer.SanitizeYear(targetYear)); return Ok(result); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("MothraId", mothraId); @@ -381,7 +382,7 @@ public async Task GetClinicianRotations(string mothraId) _logger.LogDebug("Found {RotationCount} unique rotations for clinician {MothraId}", rotations.Count, LogSanitizer.SanitizeId(mothraId)); return Ok(rotations); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("MothraId", mothraId); @@ -575,7 +576,7 @@ private List FilterCliniciansByPermissions(IEnumerable AddInstructor( { return HandleInvalidOperation(ex, correlationId); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return HandleSystemError(ex, request.RotationId!.Value, correlationId); } @@ -335,7 +337,7 @@ public async Task RemoveInstructor( userMessage, correlationId)); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error removing instructor schedule {ScheduleId} (CorrelationId: {CorrelationId})", instructorScheduleId, correlationId); @@ -414,7 +416,7 @@ public async Task SetPrimaryEvaluator( instructorScheduleId, correlationId); return Forbid(); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error setting primary evaluator for instructor schedule {ScheduleId} (CorrelationId: {CorrelationId})", instructorScheduleId, correlationId); @@ -507,7 +509,7 @@ public async Task CheckScheduleConflicts( return Ok(response); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error checking schedule conflicts for {MothraId}", LogSanitizer.SanitizeId(mothraId)); return StatusCode(500, "An error occurred while checking for schedule conflicts"); @@ -532,7 +534,7 @@ public async Task GetAuditHistory( var auditHistory = await _auditService.GetInstructorScheduleAuditHistoryAsync(instructorScheduleId, cancellationToken); return Ok(auditHistory); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error retrieving audit history for instructor schedule {ScheduleId}", instructorScheduleId); return StatusCode(500, "An error occurred while retrieving audit history"); diff --git a/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs b/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs index c6ab3e805..baefce96a 100644 --- a/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.ClinicalScheduler.Services; using Viper.Classes.SQLContext; @@ -153,7 +154,7 @@ public async Task> CanEditService(int serviceId) return Ok(new { canEdit }); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("ServiceId", serviceId); @@ -215,7 +216,7 @@ public async Task> CanEditRotation(int rotationId) return Ok(new { canEdit }); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", rotationId); @@ -277,7 +278,7 @@ public async Task> CanEditOwnSchedule(int instructorSchedul return Ok(new { canEditOwn }); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("InstructorScheduleId", instructorScheduleId); diff --git a/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs b/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs index 127115ee2..02d8603b6 100644 --- a/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/RotationsController.cs @@ -8,6 +8,7 @@ using Viper.Models.ClinicalScheduler; using Web.Authorization; using Person = Viper.Models.ClinicalScheduler.Person; +using Microsoft.Data.SqlClient; namespace Viper.Areas.ClinicalScheduler.Controllers { @@ -77,7 +78,7 @@ public async Task>> GetRotations(int? serv rotations.Count, filteredRotations.Count); return Ok(filteredRotations); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext(new Dictionary @@ -138,7 +139,7 @@ public async Task> GetRotation(int id) _logger.LogInformation("Retrieved rotation via RotationService: {RotationName}", rotation.Name); return Ok(response); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", id); @@ -240,7 +241,7 @@ public async Task> GetRotationSchedule(int id, [FromQuery] return Ok(BuildRotationScheduleResponse(rotation, targetYear, groupedSchedules, recentCliniciansList)); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("RotationId", id); @@ -305,7 +306,7 @@ join w in _context.Weeks on i.WeekId equals w.WeekId _logger.LogInformation("Retrieved {Count} rotations with scheduled weeks for year {Year} (filtered to {FilteredCount})", rotationsWithSchedules.Count, LogSanitizer.SanitizeYear(targetYear), filteredRotations.Count); return Ok(filteredRotations); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { // Store context for ApiExceptionFilter to use in logging SetExceptionContext("Year", year?.ToString() ?? "null"); diff --git a/web/Areas/RAPS/Controllers/AdGroupsController.cs b/web/Areas/RAPS/Controllers/AdGroupsController.cs index 8b28ac5f4..6b0129d98 100644 --- a/web/Areas/RAPS/Controllers/AdGroupsController.cs +++ b/web/Areas/RAPS/Controllers/AdGroupsController.cs @@ -10,6 +10,7 @@ using Viper.Classes.Utilities; using Viper.Models.RAPS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Controllers { @@ -113,7 +114,7 @@ public async Task> CreateGroup(GroupAddEdit group) OuGroup newOuGroup = await _ouGroupService.CreateRapsGroup(group.Name, group.Description); return CreatedAtAction("CreateGroup", new { id = newOuGroup.OugroupId }, newOuGroup); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { //Exception message could be indication user is trying to create a group that exists or is invalid. return ValidationProblem(ex.Message); diff --git a/web/Areas/RAPS/Controllers/RoleMembersController.cs b/web/Areas/RAPS/Controllers/RoleMembersController.cs index 8ca25941f..7981bb98a 100644 --- a/web/Areas/RAPS/Controllers/RoleMembersController.cs +++ b/web/Areas/RAPS/Controllers/RoleMembersController.cs @@ -267,7 +267,7 @@ private static void UpdateTblRoleMemberWithDto(TblRoleMember tblRoleMember, Role return vmacsResponse; } } - catch (System.Text.Json.JsonException) + catch (JsonException) { return new VmacsResponse { diff --git a/web/Areas/RAPS/Controllers/RolesController.cs b/web/Areas/RAPS/Controllers/RolesController.cs index 3000b2030..11fa0412f 100644 --- a/web/Areas/RAPS/Controllers/RolesController.cs +++ b/web/Areas/RAPS/Controllers/RolesController.cs @@ -6,6 +6,7 @@ using Viper.Classes; using Viper.Classes.SQLContext; using Viper.Models.RAPS; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Controllers { @@ -222,7 +223,7 @@ public async Task> PostTblRole(string instance, RoleCreate { return Problem("The record was not updated because it was locked. " + ex.InnerException?.Message); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return Problem("There was a problem updating the database. " + ex.InnerException?.Message); } diff --git a/web/Areas/RAPS/Services/OuGroupService.cs b/web/Areas/RAPS/Services/OuGroupService.cs index c7b555693..f1c8d3a60 100644 --- a/web/Areas/RAPS/Services/OuGroupService.cs +++ b/web/Areas/RAPS/Services/OuGroupService.cs @@ -8,6 +8,7 @@ using Viper.Classes.Utilities; using Viper.Models.RAPS; using static Viper.Areas.RAPS.Services.RAPSAuditService; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Services { @@ -45,7 +46,7 @@ public async Task> GetAllGroups(string? search) { ActiveDirectoryService.GetGroups(); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { Logger logger = LogManager.GetCurrentClassLogger(); logger.Error(ex); diff --git a/web/Areas/RAPS/Services/VMACSExport.cs b/web/Areas/RAPS/Services/VMACSExport.cs index 68ff87ac7..46aa08744 100644 --- a/web/Areas/RAPS/Services/VMACSExport.cs +++ b/web/Areas/RAPS/Services/VMACSExport.cs @@ -2,6 +2,7 @@ using System.Text; using System.Text.Encodings.Web; using System.Text.Json; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.RAPS.Models; using Viper.Classes.SQLContext; @@ -132,7 +133,7 @@ public async Task> ExportToVMACS(string instance, string? server = VmacsResponse vmacsResponse = await ParseResponse(response); RecordMessage(messages, JsonSerializer.Serialize(vmacsResponse)); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Log(LogLevel.Warn, ex); RecordMessage(messages, "Error: " + ex.Message + " " + ex.StackTrace); @@ -167,7 +168,7 @@ private static async Task ParseResponse(HttpResponseMessage respo vmacsResponse.Success = response.IsSuccessStatusCode; } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { vmacsResponse = new() { diff --git a/web/Classes/ClaimsTransformer.cs b/web/Classes/ClaimsTransformer.cs index cfc7abbb9..550d58d17 100644 --- a/web/Classes/ClaimsTransformer.cs +++ b/web/Classes/ClaimsTransformer.cs @@ -1,6 +1,8 @@ using System.Security.Claims; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.DataProtection; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Viper; using Viper.Classes; @@ -90,7 +92,7 @@ public Task TransformAsync(ClaimsPrincipal principal) } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { bool isProd = false; diff --git a/web/Classes/SitemapMiddleware.cs b/web/Classes/SitemapMiddleware.cs index 1cacea55a..352f2021d 100644 --- a/web/Classes/SitemapMiddleware.cs +++ b/web/Classes/SitemapMiddleware.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Web.Authorization; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes { @@ -85,7 +87,7 @@ public async Task Invoke(HttpContext context) await memoryStream.CopyToAsync(stream, bytes.Length); } } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { await _next(context); } diff --git a/web/Classes/UserHelper.cs b/web/Classes/UserHelper.cs index a31e51466..d851e75bc 100644 --- a/web/Classes/UserHelper.cs +++ b/web/Classes/UserHelper.cs @@ -5,6 +5,8 @@ using Viper.Models.AAUD; using Viper.Models.RAPS; using Web.Authorization; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper { @@ -270,7 +272,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return user; } } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -297,7 +299,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return currentUser; } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -329,7 +331,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return GetCurrentUser(); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; diff --git a/web/Classes/Utilities/ActiveDirectoryService.cs b/web/Classes/Utilities/ActiveDirectoryService.cs index acb3e21c3..13aa30355 100644 --- a/web/Classes/Utilities/ActiveDirectoryService.cs +++ b/web/Classes/Utilities/ActiveDirectoryService.cs @@ -3,6 +3,8 @@ using System.Net; using System.Runtime.Versioning; using Viper.Areas.RAPS.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes.Utilities { @@ -219,7 +221,7 @@ public static void AddUserToGroup(string userDn, string groupDn) group.Save(); } } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); } @@ -245,7 +247,7 @@ public static void RemoveUserFromGroup(string userDn, string groupDn) group.Save(); } } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); } diff --git a/web/Classes/Utilities/F5HttpRequest.cs b/web/Classes/Utilities/F5HttpRequest.cs index 4810961d6..784494549 100644 --- a/web/Classes/Utilities/F5HttpRequest.cs +++ b/web/Classes/Utilities/F5HttpRequest.cs @@ -1,5 +1,7 @@ using System.Net; using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes.Utilities { @@ -22,7 +24,7 @@ public async Task Send(HttpRequestMessage request, int atte { response = await _httpClient.SendAsync(request); } - catch (Exception) when (true /* placeholder */) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { response = await HandleConnectionFail(request, attemptNumber); } diff --git a/web/Classes/Utilities/IamApi.cs b/web/Classes/Utilities/IamApi.cs index 5c8cf631b..e1baf1750 100644 --- a/web/Classes/Utilities/IamApi.cs +++ b/web/Classes/Utilities/IamApi.cs @@ -4,6 +4,8 @@ using System.Web; using NLog; using Viper.Models.IAM; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes.Utilities { @@ -398,7 +400,7 @@ static private async Task> ParseResponse(HttpResponseMessage? res } } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { r.ErrorMessage = "Invalid response: " + ex.Message + "."; } diff --git a/web/Program.cs b/web/Program.cs index 78b7bf3da..9b0abd69c 100644 --- a/web/Program.cs +++ b/web/Program.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Rewrite; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; @@ -86,7 +87,7 @@ .AddSystemsManager("/" + builder.Environment.EnvironmentName, awsOptions) .AddSystemsManager("/Shared", awsOptions); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { logger.Fatal(ex, "Failed to get secrets from AWS"); } @@ -450,7 +451,7 @@ void RegisterDbContext(string connectionStringKey) where TContext : Db await ViteProxyHelpers.CopyProxyResponse(context, response); return; // Successfully proxied, don't continue to static files } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { var logger = context.RequestServices.GetRequiredService>(); logger.LogDebug(ex, "Vite server not available, falling back to static files for {Path}", @@ -582,7 +583,7 @@ void SetAwsCredentials(Logger logger) { File.Delete(awsCredentialsFilePath); } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { logger.Error(ex, $"COULD NOT DELETE THE AWS CREDENTIALS XML FILE (\"{awsCredentialsFilePath}\"). The file will need to be deleted manually."); logger.Error(ex, $"COULD NOT DELETE THE AWS CREDENTIALS XML FILE (\"{awsCredentialsFilePath}\"). The file will need to be deleted manually."); diff --git a/web/Services/EmailService.cs b/web/Services/EmailService.cs index 9842d0fa9..17f206cc1 100644 --- a/web/Services/EmailService.cs +++ b/web/Services/EmailService.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.Options; using MimeKit; using Viper.Classes.Utilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Services { @@ -219,7 +221,7 @@ public async Task IsServiceAvailableAsync() // For production, assume the SMTP server is available return true; } - catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error checking email service availability"); return false; diff --git a/web/ViteProxyHelpers.cs b/web/ViteProxyHelpers.cs index 0e8606867..40a5f225f 100644 --- a/web/ViteProxyHelpers.cs +++ b/web/ViteProxyHelpers.cs @@ -1,6 +1,8 @@ using System.Net; using System.Text.RegularExpressions; using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; namespace Web; @@ -284,7 +286,7 @@ public static async Task CopyProxyResponse(HttpContext context, HttpResponseMess { context.Response.Headers[header.Key] = header.Value.ToArray(); } - catch (Exception headerEx) when (headerEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException or System.IO.IOException) + catch (Exception headerEx) when (headerEx is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException or IOException) { // Use structured logging for header errors var safeHeaderKey = WebUtility.HtmlEncode(header.Key); @@ -367,7 +369,7 @@ public static async Task HandleProxyError(HttpContext context, Exception ex, ILo return; } } - catch (Exception fileEx) when (fileEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException or System.IO.IOException) + catch (Exception fileEx) when (fileEx is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException or IOException) { var safePath = context.Request.Path.ToString().Replace("\r", "").Replace("\n", ""); logger.LogWarning(fileEx, "Failed to serve static file fallback for {Path}", safePath);