diff --git a/web/Areas/CTS/Controllers/BundleCompetencyController.cs b/web/Areas/CTS/Controllers/BundleCompetencyController.cs index 2fcb55d0e..2b7d88fbb 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) + 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 9fb69a71f..64afdb83a 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) + 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 b1ba9cea1..18ac1587a 100644 --- a/web/Areas/CTS/Controllers/BundleController.cs +++ b/web/Areas/CTS/Controllers/BundleController.cs @@ -6,6 +6,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -140,7 +141,7 @@ public async Task> DeleteBundle(int bundleId) await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + 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 8c729ab04..4ab195663 100644 --- a/web/Areas/CTS/Controllers/CompetencyController.cs +++ b/web/Areas/CTS/Controllers/CompetencyController.cs @@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using Viper.Models.CTS; using Viper.Areas.CTS.Models; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -180,7 +181,7 @@ public async Task> DeleteCompetency(int competencyId { await context.SaveChangesAsync(); } - catch (Exception) + 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 f2a755c02..2d1c39f62 100644 --- a/web/Areas/CTS/Controllers/CourseController.cs +++ b/web/Areas/CTS/Controllers/CourseController.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 { @@ -103,7 +104,7 @@ public async Task>> SetCourseRoles(int courseId, List await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { return BadRequest("Could not set roles."); } @@ -285,7 +286,7 @@ public async Task>> UpdateSessionCompete await context.SaveChangesAsync(); await trans.CommitAsync(); } - catch (Exception) + 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 a461b41d6..91c9bf908 100644 --- a/web/Areas/CTS/Controllers/DomainController.cs +++ b/web/Areas/CTS/Controllers/DomainController.cs @@ -6,6 +6,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -92,7 +93,7 @@ public async Task> DeleteDomain(int domainId) { await context.SaveChangesAsync(); } - catch (Exception) + 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 7bbceb387..17ecd85f6 100644 --- a/web/Areas/CTS/Controllers/EpaController.cs +++ b/web/Areas/CTS/Controllers/EpaController.cs @@ -5,6 +5,7 @@ using Viper.Models.CTS; using Viper.Services; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -105,7 +106,7 @@ public async Task> DeleteEpa(int epaId) context.Entry(epa).State = EntityState.Deleted; await context.SaveChangesAsync(); } - catch (Exception ex) + 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 c9e601d3e..0d8930ccf 100644 --- a/web/Areas/CTS/Controllers/LevelsController.cs +++ b/web/Areas/CTS/Controllers/LevelsController.cs @@ -6,6 +6,7 @@ using Viper.Classes.SQLContext; using Viper.Models.CTS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.CTS.Controllers { @@ -152,7 +153,7 @@ public async Task DeleteLevel(int levelId) AdjustLevelOrders(existing); await trans.CommitAsync(); } - catch (Exception) + 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 73ee123a4..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) + 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 a762b76f1..5f257e8c0 100644 --- a/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/CliniciansController.cs @@ -6,6 +6,7 @@ using Viper.Models.ClinicalScheduler; using Web.Authorization; using Viper.Classes.Utilities; +using Microsoft.Data.SqlClient; namespace Viper.Areas.ClinicalScheduler.Controllers { @@ -334,7 +335,7 @@ public async Task GetClinicianSchedule(string mothraId, [FromQuer schedules.Count, LogSanitizer.SanitizeId(mothraId), LogSanitizer.SanitizeYear(targetYear)); return Ok(result); } - catch (Exception) + 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) + 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 IEnumerable FilterCliniciansByPermissions(IEnumerable< // All other cases (Admin, Manage, EditClnSchedules, rotation view, or service-specific permissions) see all clinicians return clinicians; } - catch (Exception ex) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error filtering clinicians by permissions. Returning unfiltered list."); return clinicians; // Return unfiltered list on error to avoid breaking functionality @@ -653,7 +654,7 @@ private bool CheckClinicianScheduleViewPermission(string targetMothraId) LogSanitizer.SanitizeId(currentUser.MothraId), LogSanitizer.SanitizeId(targetMothraId)); return false; } - catch (Exception ex) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(ex, "Error checking clinician schedule view permission for target {TargetMothraId}", LogSanitizer.SanitizeId(targetMothraId)); return false; // Deny access on error diff --git a/web/Areas/ClinicalScheduler/Controllers/InstructorScheduleController.cs b/web/Areas/ClinicalScheduler/Controllers/InstructorScheduleController.cs index 2085a186d..d189b7d09 100644 --- a/web/Areas/ClinicalScheduler/Controllers/InstructorScheduleController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/InstructorScheduleController.cs @@ -10,6 +10,8 @@ using Viper.Models.ClinicalScheduler; using Web.Authorization; using Viper.Classes.Utilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Areas.ClinicalScheduler.Controllers { @@ -106,7 +108,7 @@ public async Task AddInstructor( { return HandleInvalidOperation(ex, correlationId); } - catch (Exception ex) + 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) + 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) + 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) + 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) + 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 4779789a0..b37c871a7 100644 --- a/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs +++ b/web/Areas/ClinicalScheduler/Controllers/PermissionsController.cs @@ -4,6 +4,7 @@ using Viper.Classes.SQLContext; using Web.Authorization; using Viper.Classes.Utilities; +using Microsoft.Data.SqlClient; namespace Viper.Areas.ClinicalScheduler.Controllers { @@ -153,7 +154,7 @@ public async Task> CanEditService(int serviceId) return Ok(new { canEdit }); } - catch (Exception) + 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) + 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) + 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 fac532700..ebb33f7a1 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) + 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) + 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) + 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) + 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/Computing/Services/BiorenderStudentLookup.cs b/web/Areas/Computing/Services/BiorenderStudentLookup.cs index 5d6d3e93a..d14800730 100644 --- a/web/Areas/Computing/Services/BiorenderStudentLookup.cs +++ b/web/Areas/Computing/Services/BiorenderStudentLookup.cs @@ -94,7 +94,7 @@ static private bool IsValidEmail(string email) var addr = new System.Net.Mail.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 96eda27d9..b43f7601a 100644 --- a/web/Areas/RAPS/Controllers/AdGroupsController.cs +++ b/web/Areas/RAPS/Controllers/AdGroupsController.cs @@ -11,6 +11,7 @@ using Viper.Classes.Utilities; using Viper.Models.RAPS; using Web.Authorization; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Controllers { @@ -114,7 +115,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 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 a3cae450a..37b8f7d88 100644 --- a/web/Areas/RAPS/Controllers/RoleMembersController.cs +++ b/web/Areas/RAPS/Controllers/RoleMembersController.cs @@ -268,7 +268,7 @@ private static void UpdateTblRoleMemberWithDto(TblRoleMember tblRoleMember, Role return vmacsResponse; } } - catch + catch (JsonException) { return new VmacsResponse() { diff --git a/web/Areas/RAPS/Controllers/RolesController.cs b/web/Areas/RAPS/Controllers/RolesController.cs index cd108272a..373462f0a 100644 --- a/web/Areas/RAPS/Controllers/RolesController.cs +++ b/web/Areas/RAPS/Controllers/RolesController.cs @@ -7,6 +7,7 @@ using Viper.Classes; using Viper.Classes.SQLContext; using Viper.Models.RAPS; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Controllers { @@ -225,7 +226,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 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 4352927f0..2debbe6bb 100644 --- a/web/Areas/RAPS/Services/OuGroupService.cs +++ b/web/Areas/RAPS/Services/OuGroupService.cs @@ -9,6 +9,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 { @@ -48,7 +49,7 @@ public async Task> GetAllGroups(string? search) { ActiveDirectoryService.GetGroups(); } - catch (Exception ex) + 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 ce945db4d..3da8c92c0 100644 --- a/web/Areas/RAPS/Services/VMACSExport.cs +++ b/web/Areas/RAPS/Services/VMACSExport.cs @@ -5,6 +5,7 @@ using Viper.Areas.RAPS.Models; using Viper.Classes.SQLContext; using Viper.Classes.Utilities; +using Microsoft.Data.SqlClient; namespace Viper.Areas.RAPS.Services { @@ -131,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 DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Log(NLog.LogLevel.Warn, ex); RecordMessage(messages, "Error: " + ex.Message + " " + ex?.StackTrace); @@ -168,7 +169,7 @@ private static async Task ParseResponse(HttpResponseMessage respo vmacsResponse.Success = response.IsSuccessStatusCode; } } - catch (Exception) + 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 3a6ebed4b..35ace9172 100644 --- a/web/Classes/ClaimsTransformer.cs +++ b/web/Classes/ClaimsTransformer.cs @@ -6,6 +6,8 @@ using Viper.Classes; using Viper.Classes.SQLContext; using Viper.Models.AAUD; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Web.Authorization { @@ -89,7 +91,7 @@ public Task TransformAsync(ClaimsPrincipal principal) } - catch (Exception ex) + 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 159e17071..05d757ad0 100644 --- a/web/Classes/SitemapMiddleware.cs +++ b/web/Classes/SitemapMiddleware.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Text; using Web.Authorization; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes { @@ -84,7 +86,7 @@ public async Task Invoke(HttpContext context) await memoryStream.CopyToAsync(stream, bytes.Length); } } - catch (Exception) + 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 88853d526..498183b32 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 { @@ -291,7 +293,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return user; } } - catch (Exception ex) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -318,7 +320,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi return currentUser; } - catch (Exception ex) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { HttpHelper.Logger.Error(ex); return null; @@ -355,7 +357,7 @@ public bool HasPermission(RAPSContext? rapsContext, AaudUser? user, string permi } else { return GetCurrentUser(); } } - catch (Exception ex) + 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 ac0d950a8..870e34b6f 100644 --- a/web/Classes/Utilities/ActiveDirectoryService.cs +++ b/web/Classes/Utilities/ActiveDirectoryService.cs @@ -2,6 +2,8 @@ using System.DirectoryServices.Protocols; 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) + 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) + 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 147a30e8f..a524e9852 100644 --- a/web/Classes/Utilities/F5HttpRequest.cs +++ b/web/Classes/Utilities/F5HttpRequest.cs @@ -1,4 +1,6 @@ using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes.Utilities { @@ -21,7 +23,7 @@ public async Task Send(HttpRequestMessage request, int atte { response = await _httpClient.SendAsync(request); } - catch (Exception) + 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 2801a19b2..083711475 100644 --- a/web/Classes/Utilities/IamApi.cs +++ b/web/Classes/Utilities/IamApi.cs @@ -4,6 +4,8 @@ using System.Text.Json; using System.Web; using Viper.Models.IAM; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Classes.Utilities { @@ -449,7 +451,7 @@ static private async Task> ParseResponse(HttpResponseMessage? res } } - catch (Exception ex) + 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 5fee3318b..4aa474663 100644 --- a/web/Program.cs +++ b/web/Program.cs @@ -27,6 +27,7 @@ using Viper.Classes.SQLContext; using Web; using Web.Authorization; +using Microsoft.Data.SqlClient; // Load .env.local for local development only (multiple-instance support) // Avoid loading in production - guard by ASPNETCORE_ENVIRONMENT. @@ -75,7 +76,7 @@ .AddSystemsManager("/" + builder.Environment.EnvironmentName, awsOptions) .AddSystemsManager("/Shared", awsOptions); } - catch (Exception ex) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { logger.Fatal(ex, "Failed to get secrets from AWS"); } @@ -439,7 +440,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 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}", @@ -523,7 +524,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"); @@ -570,7 +573,7 @@ void SetAwsCredentials(Logger logger) { File.Delete(awsCredentialsFilePath); } - catch (Exception ex) + 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 1bb5f9fae..b11866d36 100644 --- a/web/Services/EmailService.cs +++ b/web/Services/EmailService.cs @@ -4,6 +4,8 @@ using Microsoft.Extensions.Options; using MimeKit; using Viper.Classes.Utilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.Data.SqlClient; namespace Viper.Services { @@ -218,7 +220,7 @@ public async Task IsServiceAvailableAsync() // For production, assume the SMTP server is available return true; } - catch (Exception ex) + 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 fa939bead..fada34ff3 100644 --- a/web/ViteProxyHelpers.cs +++ b/web/ViteProxyHelpers.cs @@ -1,5 +1,7 @@ using System.Net; using System.Text.RegularExpressions; +using Microsoft.Data.SqlClient; +using Microsoft.EntityFrameworkCore; namespace Web; @@ -278,7 +280,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 DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException or IOException) { // Use structured logging for header errors var safeHeaderKey = WebUtility.HtmlEncode(header.Key); @@ -361,7 +363,7 @@ public static async Task HandleProxyError(HttpContext context, Exception ex, ILo return; } } - catch (Exception fileEx) + 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);