From 125d2a967de159e83442ea4c7ab402f5521b5be2 Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Tue, 12 May 2026 23:24:50 -0700 Subject: [PATCH 1/3] refactor(ClinicalScheduler): catch specific exceptions in services CodeQL cs/catch-of-all-exceptions: replace blanket `catch (Exception)` in 8 ClinicalScheduler service files with a `when` filter restricting to the exception families these methods actually need to wrap (DbUpdateException, SqlException, InvalidOperationException, OperationCanceledException). Anything outside that set now propagates unchanged. Four fire-and-forget catches around post-transaction work (email notifications and audit logging that must not roll back successful DB changes) are kept intentionally broad and marked with `#pragma warning disable CA1031` explaining why. Test EmailNotificationTest.RemoveInstructorScheduleAsync_EmailServiceFails_StillCompletesRemoval enforces this resilience contract. --- .../Services/InstructorScheduleService.cs | 2 +- .../Services/PersonService.cs | 12 ++++----- .../Services/RotationService.cs | 14 +++++----- .../Services/ScheduleAuditService.cs | 6 ++--- .../Services/ScheduleEditService.cs | 27 ++++++++++++------- .../Services/SchedulePermissionService.cs | 16 +++++------ .../Services/StudentScheduleService.cs | 2 +- .../ClinicalScheduler/Services/WeekService.cs | 8 +++--- 8 files changed, 47 insertions(+), 40 deletions(-) diff --git a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs index 06b662743..25d3f3fd7 100644 --- a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs @@ -104,7 +104,7 @@ public async Task> GetInstructorScheduleAsync( _logger.LogInformation("Found {Count} instructor schedules", schedules.Count); return schedules; } - 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 instructor schedules"); throw new InvalidOperationException("Failed to retrieve instructor schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/PersonService.cs b/web/Areas/ClinicalScheduler/Services/PersonService.cs index f80665778..e8acddaab 100644 --- a/web/Areas/ClinicalScheduler/Services/PersonService.cs +++ b/web/Areas/ClinicalScheduler/Services/PersonService.cs @@ -81,7 +81,7 @@ public PersonService(ILogger logger, ClinicalSchedulerContext con return person; } - 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 person data for MothraId: {MothraId}", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve person data for MothraId {LogSanitizer.SanitizeId(mothraId)}", ex); @@ -139,7 +139,7 @@ public async Task> GetCliniciansByYearAsync(int year, _logger.LogInformation("Found {ClinicianCount} clinicians for year {Year} with person names from vPerson view", clinicians.Count, year); return clinicians; } - 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 clinicians for year: {Year}", year); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year {year}. Check database connectivity and view permissions.", ex); @@ -209,7 +209,7 @@ public async Task> GetCliniciansByGradYearRangeAsync(int _logger.LogError(ex, "Database error retrieving clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Database error retrieving clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); } - 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 clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); @@ -240,7 +240,7 @@ public async Task> GetAllMothraIdsAsync(CancellationToken cancellat _logger.LogInformation("Found {Count} unique MothraIds in Clinical Scheduler data", mothraIds.Count); return mothraIds; } - 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 unique MothraIds"); throw new InvalidOperationException("Failed to retrieve unique MothraIds from database", ex); @@ -277,7 +277,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca _logger.LogDebug("Found {Count} active employee affiliates from AAUD", allAffiliates.Count); return allAffiliates; } - 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 active employee affiliates from AAUD"); throw new InvalidOperationException("Failed to retrieve active employee affiliates from AAUD database", ex); @@ -325,7 +325,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca return clinician; } - 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 clinician data for MothraId: {MothraId} from AAUD", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve clinician data for MothraId {LogSanitizer.SanitizeId(mothraId)} from AAUD", ex); diff --git a/web/Areas/ClinicalScheduler/Services/RotationService.cs b/web/Areas/ClinicalScheduler/Services/RotationService.cs index 59f0a664e..fe3318ecc 100644 --- a/web/Areas/ClinicalScheduler/Services/RotationService.cs +++ b/web/Areas/ClinicalScheduler/Services/RotationService.cs @@ -45,7 +45,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell rotations.Count); return rotations.Select(r => r.ToDto()).ToList(); } - 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 rotations from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve rotations from Clinical Scheduler database", ex); @@ -82,7 +82,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell return rotation?.ToDto(); } - 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 rotation by ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve rotation with ID {rotationId}", ex); @@ -124,7 +124,7 @@ public async Task> GetRotationsByCourseAsync(string courseNumber, return rotations; } - 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 rotations by course - CourseNumber: {CourseNumber}, SubjectCode: {SubjectCode}", courseNumber, subjectCode); @@ -154,7 +154,7 @@ public async Task> GetRotationsByServiceAsync(int serviceId, C _logger.LogInformation("Retrieved {Count} rotations for service ID: {ServiceId}", rotations.Count, serviceId); return rotations.Select(r => r.ToDto()).ToList(); } - 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 rotations by service ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve rotations for service ID {serviceId}", ex); @@ -180,7 +180,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat _logger.LogInformation("Retrieved {Count} services from Clinical Scheduler", services.Count); return services.Select(s => s.ToDto()).ToList(); } - 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 services from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve services from Clinical Scheduler database", ex); @@ -215,7 +215,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat return service?.ToDto(); } - 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 service by ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve service with ID {serviceId}", ex); @@ -265,7 +265,7 @@ public async Task> GetInstructorSchedulesByRotationAsyn return schedules; } - 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 instructor schedules for rotation ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve instructor schedules for rotation ID {rotationId}", ex); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs index e0f5ec01a..d328559fe 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs @@ -114,7 +114,7 @@ public async Task> GetInstructorScheduleAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - 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); throw new InvalidOperationException($"Failed to retrieve audit history for instructor schedule {instructorScheduleId}. Please try again or contact support if the problem persists.", ex); @@ -134,7 +134,7 @@ public async Task> GetRotationWeekAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - 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 rotation {RotationId}, week {WeekId}", rotationId, weekId); throw new InvalidOperationException($"Failed to retrieve audit history for rotation {rotationId}, week {weekId}. Please try again or contact support if the problem persists.", ex); @@ -179,7 +179,7 @@ private async Task CreateAuditEntryAsync( return auditEntry; } - 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 creating audit entry for action {Action}, {MothraId} on rotation {RotationId}, week {WeekId}", action, LogSanitizer.SanitizeId(mothraId), rotationId, weekId); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs index f8a02c9e0..b31a762c3 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs @@ -216,7 +216,9 @@ await _auditService.LogPrimaryEvaluatorSetAsync( } #pragma warning restore S3267 } +#pragma warning disable CA1031 // Intentional broad catch: post-transaction work (email/audit notifications) must not roll back the successful database changes above. catch (Exception postTransactionEx) +#pragma warning restore CA1031 { // Log warning but don't fail the operation - the database changes were successful _logger.LogWarning(postTransactionEx, "Post-transaction operations failed for instructor {MothraId} in rotation {RotationId}, but database changes were successful", @@ -238,7 +240,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( // Re-throw InvalidOperationException without wrapping (includes "already scheduled" messages) throw; } - catch (Exception saveEx) + catch (Exception saveEx) when (saveEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(saveEx, "Database save failed for MothraId='{MothraId}', RotationId={RotationId}, WeekIds=[{WeekIds}]", LogSanitizer.SanitizeId(mothraId), rotationId, string.Join(",", weekIds)); @@ -332,7 +334,9 @@ await _auditService.LogInstructorRemovedAsync( await HandlePrimaryEvaluatorRemovalAsync(schedule, currentUser.MothraId, cancellationToken); } } +#pragma warning disable CA1031 // Intentional broad catch: post-transaction work (email/audit notifications) must not roll back the successful database changes above. catch (Exception postTransactionEx) +#pragma warning restore CA1031 { // Log warning but don't fail the operation - the database changes were successful _logger.LogWarning(postTransactionEx, "Post-transaction operations failed for instructor removal {ScheduleId}, but database changes were successful", @@ -354,7 +358,7 @@ await _auditService.LogInstructorRemovedAsync( // Re-throw InvalidOperationException without wrapping (includes "Cannot remove primary evaluator" message) throw; } - 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}", instructorScheduleId); throw new InvalidOperationException($"Failed to remove instructor schedule. Please try again or contact support if the problem persists.", ex); @@ -451,7 +455,9 @@ await _auditService.LogPrimaryEvaluatorSetAsync( await HandlePrimaryEvaluatorRemovalAsync(schedule, currentUser.MothraId, cancellationToken, null, requiresPrimaryEvaluator); } } +#pragma warning disable CA1031 // Intentional broad catch: post-transaction work (email/audit notifications) must not roll back the successful database changes above. catch (Exception postTransactionEx) +#pragma warning restore CA1031 { // Log warning but don't fail the operation - the database changes were successful _logger.LogWarning(postTransactionEx, "Post-transaction operations failed for primary evaluator update {ScheduleId}, but database changes were successful", @@ -463,7 +469,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( return (true, previousPrimaryName); } - 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} to {IsPrimary}", instructorScheduleId, isPrimary); throw new InvalidOperationException($"Failed to update primary evaluator status. Please try again or contact support if the problem persists.", ex); @@ -488,7 +494,7 @@ public async Task CanRemoveInstructorAsync( // All instructors can now be removed, including primary evaluators 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 if instructor schedule {ScheduleId} can be removed", instructorScheduleId); return false; @@ -530,7 +536,7 @@ public async Task> GetOtherRotationSchedulesAsync( return await query.ToListAsync(cancellationToken); } - 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 other rotation schedules for {MothraId} on weeks {WeekIds} for grad year {GradYear}", LogSanitizer.SanitizeId(mothraId), string.Join(",", weekIds), LogSanitizer.SanitizeYear(gradYear)); @@ -558,7 +564,7 @@ public async Task> GetScheduledInstructorsAsync( .Where(s => s.RotationId == rotationId && weekIds.Contains(s.WeekId)) .ToListAsync(cancellationToken); } - 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 getting scheduled instructors for rotation {RotationId} on weeks {WeekIds}", rotationId, string.Join(",", weekIds)); throw new InvalidOperationException($"Failed to retrieve scheduled instructors. Please try again or contact support if the problem persists.", ex); @@ -661,7 +667,7 @@ private async Task SendPrimaryEvaluatorRemovedNotificationAsync(InstructorSchedu } } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogWarning(ex, "Could not retrieve instructor name for {MothraId} in email notification", LogSanitizer.SanitizeId(schedule.MothraId)); } @@ -694,7 +700,7 @@ await _context.Entry(schedule) weekNumber = weekGradYear.WeekNum.ToString(); } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogWarning(ex, "Could not retrieve week number for {WeekId} in email notification", schedule.WeekId); } @@ -719,7 +725,7 @@ await _context.Entry(schedule) : ""; } } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogWarning(ex, "Could not retrieve modifier information for {MothraId} in email notification", modifiedByMothraId); } @@ -770,9 +776,10 @@ await _emailService.SendEmailAsync( _logger.LogInformation("No notification recipients configured for Primary Evaluator Removal; skipped email. Rotation={RotationName}, Week={WeekNumber}", rotationName, weekNumber); } } +#pragma warning disable CA1031 // Intentional broad catch: email notification is secondary to the schedule removal; any failure must be logged but not propagated. catch (Exception ex) +#pragma warning restore CA1031 { - // Log error but don't fail the transaction - email is secondary to the schedule removal _logger.LogError(ex, "Failed to send primary evaluator removal notification for {MothraId} from rotation {RotationId} week {WeekId} (rotation: {RotationName})", LogSanitizer.SanitizeId(schedule.MothraId), schedule.RotationId, schedule.WeekId, schedule.Rotation?.Name ?? "Unknown"); } diff --git a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs index 660729fd0..dd01a10ea 100644 --- a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs +++ b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs @@ -87,7 +87,7 @@ public async Task HasEditPermissionForServiceAsync(int serviceId, Cancella return hasPermission; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var currentUser = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and service {ServiceId}", LogSanitizer.SanitizeId(currentUser?.MothraId), serviceId); @@ -114,7 +114,7 @@ public async Task HasEditPermissionForRotationAsync(int rotationId, Cancel return await HasEditPermissionForServiceAsync(rotation.ServiceId, cancellationToken); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and rotation {RotationId}", LogSanitizer.SanitizeId(user?.MothraId), rotationId); @@ -150,7 +150,7 @@ public async Task> GetUserEditableServicesAsync(CancellationToken return editableServices; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting editable services for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -183,7 +183,7 @@ public async Task> GetUserServicePermissionsAsync(Cancella return permissions; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting service permissions for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -212,7 +212,7 @@ public async Task GetRequiredPermissionForServiceAsync(int serviceId, Ca _logger.LogDebug("Required permission for service {ServiceId}: {RequiredPermission}", serviceId, requiredPermission); return requiredPermission; } - 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 getting required permission for service {ServiceId}", serviceId); return ClinicalSchedulePermissions.Manage; @@ -258,7 +258,7 @@ public async Task CanEditOwnScheduleAsync(int instructorScheduleId, Cancel return canEdit; } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking own schedule permissions for user {MothraId} and instructor schedule {InstructorScheduleId}", @@ -304,7 +304,7 @@ public Task CheckStudentScheduleParamsAsync(string? mothraId, int? rotatio _logger.LogDebug("User {MothraId} denied access to student schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking student schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -346,7 +346,7 @@ public Task CheckInstructorScheduleParamsAsync(string? mothraId, int? rota _logger.LogDebug("User {MothraId} denied access to instructor schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - catch (Exception ex) + catch (Exception ex) when (ex is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking instructor schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); diff --git a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs index 5b2e9b93b..c9d6b204d 100644 --- a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs @@ -110,7 +110,7 @@ public async Task> GetStudentScheduleAsync( _logger.LogInformation("Found {Count} student schedules", result.Count); return result; } - 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 student schedules"); throw new InvalidOperationException("Failed to retrieve student schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/WeekService.cs b/web/Areas/ClinicalScheduler/Services/WeekService.cs index 00ed34165..61dc063c9 100644 --- a/web/Areas/ClinicalScheduler/Services/WeekService.cs +++ b/web/Areas/ClinicalScheduler/Services/WeekService.cs @@ -48,7 +48,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weeks.Count, gradYear, includeExtendedRotation); return weeks.ToDto(); } - 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 weeks for grad year {GradYear}: {ErrorMessage}", gradYear, ex.Message); throw new InvalidOperationException($"Failed to retrieve weeks for graduation year {gradYear}", ex); @@ -89,7 +89,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weekId, week.GradYear, week.WeekNum); return week.ToDto(); } - 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 week {WeekId} for grad year {GradYear}", weekId, gradYear); throw new InvalidOperationException($"Failed to retrieve week {weekId} for graduation year {gradYear}", ex); @@ -130,7 +130,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende _logger.LogInformation("Current week is {WeekNum} for grad year {GradYear}", week.WeekNum, week.GradYear); return week.ToDto(); } - 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 current week for grad year {GradYear}", gradYear); throw new InvalidOperationException($"Failed to retrieve current week for graduation year {gradYear}", ex); @@ -174,7 +174,7 @@ public async Task> GetWeeksByDateRangeAsync(DateTime? startDate = weeks.Count, startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none"); return weeks.ToDto(); } - 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 weeks for date range {StartDate} to {EndDate}", startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none"); From f5dbd3447907a0b5db498cec765a56c869bf9db7 Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Wed, 13 May 2026 01:42:03 -0700 Subject: [PATCH 2/3] chore(resharper): drop redundant namespace qualifiers in catch filters ReSharper RedundantNameQualifier flagged all 45 occurrences of Microsoft.EntityFrameworkCore.DbUpdateException and Microsoft.Data.SqlClient.SqlException in the when-filtered catches introduced by codeql/5. Replaced with the unqualified type names; 'using Microsoft.Data.SqlClient;' added to the 7 files that didn't already have it. --- .../Services/InstructorScheduleService.cs | 3 ++- .../Services/PersonService.cs | 12 ++++++------ .../Services/RotationService.cs | 15 ++++++++------- .../Services/ScheduleAuditService.cs | 7 ++++--- .../Services/ScheduleEditService.cs | 19 ++++++++++--------- .../Services/SchedulePermissionService.cs | 17 +++++++++-------- .../Services/StudentScheduleService.cs | 3 ++- .../ClinicalScheduler/Services/WeekService.cs | 9 +++++---- 8 files changed, 46 insertions(+), 39 deletions(-) diff --git a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs index 25d3f3fd7..bf244551f 100644 --- a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Classes.SQLContext; using Viper.Models.CTS; @@ -104,7 +105,7 @@ public async Task> GetInstructorScheduleAsync( _logger.LogInformation("Found {Count} instructor schedules", schedules.Count); return schedules; } - 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 instructor schedules"); throw new InvalidOperationException("Failed to retrieve instructor schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/PersonService.cs b/web/Areas/ClinicalScheduler/Services/PersonService.cs index e8acddaab..328921660 100644 --- a/web/Areas/ClinicalScheduler/Services/PersonService.cs +++ b/web/Areas/ClinicalScheduler/Services/PersonService.cs @@ -81,7 +81,7 @@ public PersonService(ILogger logger, ClinicalSchedulerContext con return person; } - 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 person data for MothraId: {MothraId}", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve person data for MothraId {LogSanitizer.SanitizeId(mothraId)}", ex); @@ -139,7 +139,7 @@ public async Task> GetCliniciansByYearAsync(int year, _logger.LogInformation("Found {ClinicianCount} clinicians for year {Year} with person names from vPerson view", clinicians.Count, year); return clinicians; } - 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 clinicians for year: {Year}", year); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year {year}. Check database connectivity and view permissions.", ex); @@ -209,7 +209,7 @@ public async Task> GetCliniciansByGradYearRangeAsync(int _logger.LogError(ex, "Database error retrieving clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Database error retrieving clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); } - 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 clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); @@ -240,7 +240,7 @@ public async Task> GetAllMothraIdsAsync(CancellationToken cancellat _logger.LogInformation("Found {Count} unique MothraIds in Clinical Scheduler data", mothraIds.Count); return mothraIds; } - 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 unique MothraIds"); throw new InvalidOperationException("Failed to retrieve unique MothraIds from database", ex); @@ -277,7 +277,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca _logger.LogDebug("Found {Count} active employee affiliates from AAUD", allAffiliates.Count); return allAffiliates; } - 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 active employee affiliates from AAUD"); throw new InvalidOperationException("Failed to retrieve active employee affiliates from AAUD database", ex); @@ -325,7 +325,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca return clinician; } - 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 clinician data for MothraId: {MothraId} from AAUD", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve clinician data for MothraId {LogSanitizer.SanitizeId(mothraId)} from AAUD", ex); diff --git a/web/Areas/ClinicalScheduler/Services/RotationService.cs b/web/Areas/ClinicalScheduler/Services/RotationService.cs index fe3318ecc..c46aad757 100644 --- a/web/Areas/ClinicalScheduler/Services/RotationService.cs +++ b/web/Areas/ClinicalScheduler/Services/RotationService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.ClinicalScheduler.Extensions; using Viper.Areas.ClinicalScheduler.Models.DTOs.Responses; @@ -45,7 +46,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell rotations.Count); return rotations.Select(r => r.ToDto()).ToList(); } - 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 rotations from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve rotations from Clinical Scheduler database", ex); @@ -82,7 +83,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell return rotation?.ToDto(); } - 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 rotation by ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve rotation with ID {rotationId}", ex); @@ -124,7 +125,7 @@ public async Task> GetRotationsByCourseAsync(string courseNumber, return rotations; } - 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 rotations by course - CourseNumber: {CourseNumber}, SubjectCode: {SubjectCode}", courseNumber, subjectCode); @@ -154,7 +155,7 @@ public async Task> GetRotationsByServiceAsync(int serviceId, C _logger.LogInformation("Retrieved {Count} rotations for service ID: {ServiceId}", rotations.Count, serviceId); return rotations.Select(r => r.ToDto()).ToList(); } - 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 rotations by service ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve rotations for service ID {serviceId}", ex); @@ -180,7 +181,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat _logger.LogInformation("Retrieved {Count} services from Clinical Scheduler", services.Count); return services.Select(s => s.ToDto()).ToList(); } - 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 services from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve services from Clinical Scheduler database", ex); @@ -215,7 +216,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat return service?.ToDto(); } - 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 service by ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve service with ID {serviceId}", ex); @@ -265,7 +266,7 @@ public async Task> GetInstructorSchedulesByRotationAsyn return schedules; } - 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 instructor schedules for rotation ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve instructor schedules for rotation ID {rotationId}", ex); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs index d328559fe..fe3f7c666 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Classes.SQLContext; using Viper.Models.ClinicalScheduler; @@ -114,7 +115,7 @@ public async Task> GetInstructorScheduleAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - 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); throw new InvalidOperationException($"Failed to retrieve audit history for instructor schedule {instructorScheduleId}. Please try again or contact support if the problem persists.", ex); @@ -134,7 +135,7 @@ public async Task> GetRotationWeekAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - 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 rotation {RotationId}, week {WeekId}", rotationId, weekId); throw new InvalidOperationException($"Failed to retrieve audit history for rotation {rotationId}, week {weekId}. Please try again or contact support if the problem persists.", ex); @@ -179,7 +180,7 @@ private async Task CreateAuditEntryAsync( return auditEntry; } - 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 creating audit entry for action {Action}, {MothraId} on rotation {RotationId}, week {WeekId}", action, LogSanitizer.SanitizeId(mothraId), rotationId, weekId); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs index b31a762c3..b2e20e646 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Viper.Areas.ClinicalScheduler.EmailTemplates.Models; @@ -240,7 +241,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( // Re-throw InvalidOperationException without wrapping (includes "already scheduled" messages) throw; } - catch (Exception saveEx) when (saveEx is Microsoft.EntityFrameworkCore.DbUpdateException or Microsoft.Data.SqlClient.SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception saveEx) when (saveEx is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) { _logger.LogError(saveEx, "Database save failed for MothraId='{MothraId}', RotationId={RotationId}, WeekIds=[{WeekIds}]", LogSanitizer.SanitizeId(mothraId), rotationId, string.Join(",", weekIds)); @@ -358,7 +359,7 @@ await _auditService.LogInstructorRemovedAsync( // Re-throw InvalidOperationException without wrapping (includes "Cannot remove primary evaluator" message) throw; } - 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}", instructorScheduleId); throw new InvalidOperationException($"Failed to remove instructor schedule. Please try again or contact support if the problem persists.", ex); @@ -469,7 +470,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( return (true, previousPrimaryName); } - 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} to {IsPrimary}", instructorScheduleId, isPrimary); throw new InvalidOperationException($"Failed to update primary evaluator status. Please try again or contact support if the problem persists.", ex); @@ -494,7 +495,7 @@ public async Task CanRemoveInstructorAsync( // All instructors can now be removed, including primary evaluators 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 if instructor schedule {ScheduleId} can be removed", instructorScheduleId); return false; @@ -536,7 +537,7 @@ public async Task> GetOtherRotationSchedulesAsync( return await query.ToListAsync(cancellationToken); } - 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 other rotation schedules for {MothraId} on weeks {WeekIds} for grad year {GradYear}", LogSanitizer.SanitizeId(mothraId), string.Join(",", weekIds), LogSanitizer.SanitizeYear(gradYear)); @@ -564,7 +565,7 @@ public async Task> GetScheduledInstructorsAsync( .Where(s => s.RotationId == rotationId && weekIds.Contains(s.WeekId)) .ToListAsync(cancellationToken); } - 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 getting scheduled instructors for rotation {RotationId} on weeks {WeekIds}", rotationId, string.Join(",", weekIds)); throw new InvalidOperationException($"Failed to retrieve scheduled instructors. Please try again or contact support if the problem persists.", ex); @@ -667,7 +668,7 @@ private async Task SendPrimaryEvaluatorRemovedNotificationAsync(InstructorSchedu } } } - 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.LogWarning(ex, "Could not retrieve instructor name for {MothraId} in email notification", LogSanitizer.SanitizeId(schedule.MothraId)); } @@ -700,7 +701,7 @@ await _context.Entry(schedule) weekNumber = weekGradYear.WeekNum.ToString(); } } - 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.LogWarning(ex, "Could not retrieve week number for {WeekId} in email notification", schedule.WeekId); } @@ -725,7 +726,7 @@ await _context.Entry(schedule) : ""; } } - 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.LogWarning(ex, "Could not retrieve modifier information for {MothraId} in email notification", modifiedByMothraId); } diff --git a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs index dd01a10ea..9c08550c0 100644 --- a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs +++ b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Classes.SQLContext; using Viper.Models.AAUD; @@ -87,7 +88,7 @@ public async Task HasEditPermissionForServiceAsync(int serviceId, Cancella return hasPermission; } - 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 currentUser = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and service {ServiceId}", LogSanitizer.SanitizeId(currentUser?.MothraId), serviceId); @@ -114,7 +115,7 @@ public async Task HasEditPermissionForRotationAsync(int rotationId, Cancel return await HasEditPermissionForServiceAsync(rotation.ServiceId, cancellationToken); } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and rotation {RotationId}", LogSanitizer.SanitizeId(user?.MothraId), rotationId); @@ -150,7 +151,7 @@ public async Task> GetUserEditableServicesAsync(CancellationToken return editableServices; } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting editable services for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -183,7 +184,7 @@ public async Task> GetUserServicePermissionsAsync(Cancella return permissions; } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting service permissions for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -212,7 +213,7 @@ public async Task GetRequiredPermissionForServiceAsync(int serviceId, Ca _logger.LogDebug("Required permission for service {ServiceId}: {RequiredPermission}", serviceId, requiredPermission); return requiredPermission; } - 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 getting required permission for service {ServiceId}", serviceId); return ClinicalSchedulePermissions.Manage; @@ -258,7 +259,7 @@ public async Task CanEditOwnScheduleAsync(int instructorScheduleId, Cancel return canEdit; } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking own schedule permissions for user {MothraId} and instructor schedule {InstructorScheduleId}", @@ -304,7 +305,7 @@ public Task CheckStudentScheduleParamsAsync(string? mothraId, int? rotatio _logger.LogDebug("User {MothraId} denied access to student schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking student schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -346,7 +347,7 @@ public Task CheckInstructorScheduleParamsAsync(string? mothraId, int? rota _logger.LogDebug("User {MothraId} denied access to instructor schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - 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 user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking instructor schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); diff --git a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs index c9d6b204d..1ea6f8044 100644 --- a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.CTS.Models; using Viper.Classes.SQLContext; @@ -110,7 +111,7 @@ public async Task> GetStudentScheduleAsync( _logger.LogInformation("Found {Count} student schedules", result.Count); return result; } - 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 student schedules"); throw new InvalidOperationException("Failed to retrieve student schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/WeekService.cs b/web/Areas/ClinicalScheduler/Services/WeekService.cs index 61dc063c9..f34078f54 100644 --- a/web/Areas/ClinicalScheduler/Services/WeekService.cs +++ b/web/Areas/ClinicalScheduler/Services/WeekService.cs @@ -1,3 +1,4 @@ +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Viper.Areas.ClinicalScheduler.Extensions; using Viper.Areas.ClinicalScheduler.Models.DTOs.Responses; @@ -48,7 +49,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weeks.Count, gradYear, includeExtendedRotation); return weeks.ToDto(); } - 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 weeks for grad year {GradYear}: {ErrorMessage}", gradYear, ex.Message); throw new InvalidOperationException($"Failed to retrieve weeks for graduation year {gradYear}", ex); @@ -89,7 +90,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weekId, week.GradYear, week.WeekNum); return week.ToDto(); } - 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 week {WeekId} for grad year {GradYear}", weekId, gradYear); throw new InvalidOperationException($"Failed to retrieve week {weekId} for graduation year {gradYear}", ex); @@ -130,7 +131,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende _logger.LogInformation("Current week is {WeekNum} for grad year {GradYear}", week.WeekNum, week.GradYear); return week.ToDto(); } - 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 current week for grad year {GradYear}", gradYear); throw new InvalidOperationException($"Failed to retrieve current week for graduation year {gradYear}", ex); @@ -174,7 +175,7 @@ public async Task> GetWeeksByDateRangeAsync(DateTime? startDate = weeks.Count, startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none"); return weeks.ToDto(); } - 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 weeks for date range {StartDate} to {EndDate}", startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none"); From 39e16dbca95c99687c463115e01e1f083dc97f7d Mon Sep 17 00:00:00 2001 From: Rex Lorenzo Date: Thu, 14 May 2026 13:42:01 -0700 Subject: [PATCH 3/3] fix(ClinicalScheduler): correct catch filters in services Two related fixes to the filtered catches added in c269ad7d: 1. OperationCanceledException no longer swallowed. The filters caught cancellation alongside data-access failures, wrapping it as InvalidOperationException (or, in SchedulePermissionService, silently returning `false`/empty results). Dropping it from the `when` filters lets cooperative cancellation propagate naturally. 2. Unreachable types removed from three filters that listed exceptions already handled by a dedicated catch clause above them: - PersonService AddRangeInstructorScheduleAsync: SqlException is caught at the preceding `catch (SqlException ex)`. - ScheduleEditService AddInstructorScheduleAsync and RemoveInstructorScheduleAsync: InvalidOperationException is rethrown by the preceding `catch (InvalidOperationException)` passthrough. --- .../Services/InstructorScheduleService.cs | 2 +- .../Services/PersonService.cs | 12 ++++++------ .../Services/RotationService.cs | 14 +++++++------- .../Services/ScheduleAuditService.cs | 6 +++--- .../Services/ScheduleEditService.cs | 18 +++++++++--------- .../Services/SchedulePermissionService.cs | 16 ++++++++-------- .../Services/StudentScheduleService.cs | 2 +- .../ClinicalScheduler/Services/WeekService.cs | 8 ++++---- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs index bf244551f..898c527d2 100644 --- a/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/InstructorScheduleService.cs @@ -105,7 +105,7 @@ public async Task> GetInstructorScheduleAsync( _logger.LogInformation("Found {Count} instructor schedules", schedules.Count); return schedules; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving instructor schedules"); throw new InvalidOperationException("Failed to retrieve instructor schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/PersonService.cs b/web/Areas/ClinicalScheduler/Services/PersonService.cs index 328921660..a407e0a3e 100644 --- a/web/Areas/ClinicalScheduler/Services/PersonService.cs +++ b/web/Areas/ClinicalScheduler/Services/PersonService.cs @@ -81,7 +81,7 @@ public PersonService(ILogger logger, ClinicalSchedulerContext con return person; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving person data for MothraId: {MothraId}", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve person data for MothraId {LogSanitizer.SanitizeId(mothraId)}", ex); @@ -139,7 +139,7 @@ public async Task> GetCliniciansByYearAsync(int year, _logger.LogInformation("Found {ClinicianCount} clinicians for year {Year} with person names from vPerson view", clinicians.Count, year); return clinicians; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving clinicians for year: {Year}", year); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year {year}. Check database connectivity and view permissions.", ex); @@ -209,7 +209,7 @@ public async Task> GetCliniciansByGradYearRangeAsync(int _logger.LogError(ex, "Database error retrieving clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Database error retrieving clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving clinicians for grad year range {StartYear}-{EndYear}", LogSanitizer.SanitizeYear(startGradYear), LogSanitizer.SanitizeYear(endGradYear)); throw new InvalidOperationException($"Failed to retrieve clinicians for grad year range {LogSanitizer.SanitizeYear(startGradYear)}-{LogSanitizer.SanitizeYear(endGradYear)}", ex); @@ -240,7 +240,7 @@ public async Task> GetAllMothraIdsAsync(CancellationToken cancellat _logger.LogInformation("Found {Count} unique MothraIds in Clinical Scheduler data", mothraIds.Count); return mothraIds; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving unique MothraIds"); throw new InvalidOperationException("Failed to retrieve unique MothraIds from database", ex); @@ -277,7 +277,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca _logger.LogDebug("Found {Count} active employee affiliates from AAUD", allAffiliates.Count); return allAffiliates; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving active employee affiliates from AAUD"); throw new InvalidOperationException("Failed to retrieve active employee affiliates from AAUD database", ex); @@ -325,7 +325,7 @@ public async Task> GetAllActiveEmployeeAffiliatesAsync(Ca return clinician; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving clinician data for MothraId: {MothraId} from AAUD", LogSanitizer.SanitizeId(mothraId)); throw new InvalidOperationException($"Failed to retrieve clinician data for MothraId {LogSanitizer.SanitizeId(mothraId)} from AAUD", ex); diff --git a/web/Areas/ClinicalScheduler/Services/RotationService.cs b/web/Areas/ClinicalScheduler/Services/RotationService.cs index c46aad757..7aaa8ef3f 100644 --- a/web/Areas/ClinicalScheduler/Services/RotationService.cs +++ b/web/Areas/ClinicalScheduler/Services/RotationService.cs @@ -46,7 +46,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell rotations.Count); return rotations.Select(r => r.ToDto()).ToList(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving rotations from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve rotations from Clinical Scheduler database", ex); @@ -83,7 +83,7 @@ public async Task> GetRotationsAsync(CancellationToken cancell return rotation?.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving rotation by ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve rotation with ID {rotationId}", ex); @@ -125,7 +125,7 @@ public async Task> GetRotationsByCourseAsync(string courseNumber, return rotations; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving rotations by course - CourseNumber: {CourseNumber}, SubjectCode: {SubjectCode}", courseNumber, subjectCode); @@ -155,7 +155,7 @@ public async Task> GetRotationsByServiceAsync(int serviceId, C _logger.LogInformation("Retrieved {Count} rotations for service ID: {ServiceId}", rotations.Count, serviceId); return rotations.Select(r => r.ToDto()).ToList(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving rotations by service ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve rotations for service ID {serviceId}", ex); @@ -181,7 +181,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat _logger.LogInformation("Retrieved {Count} services from Clinical Scheduler", services.Count); return services.Select(s => s.ToDto()).ToList(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving services from Clinical Scheduler"); throw new InvalidOperationException("Failed to retrieve services from Clinical Scheduler database", ex); @@ -216,7 +216,7 @@ public async Task> GetServicesAsync(CancellationToken cancellat return service?.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving service by ID: {ServiceId}", serviceId); throw new InvalidOperationException($"Failed to retrieve service with ID {serviceId}", ex); @@ -266,7 +266,7 @@ public async Task> GetInstructorSchedulesByRotationAsyn return schedules; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving instructor schedules for rotation ID: {RotationId}", rotationId); throw new InvalidOperationException($"Failed to retrieve instructor schedules for rotation ID {rotationId}", ex); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs index fe3f7c666..9425aa642 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleAuditService.cs @@ -115,7 +115,7 @@ public async Task> GetInstructorScheduleAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving audit history for instructor schedule {ScheduleId}", instructorScheduleId); throw new InvalidOperationException($"Failed to retrieve audit history for instructor schedule {instructorScheduleId}. Please try again or contact support if the problem persists.", ex); @@ -135,7 +135,7 @@ public async Task> GetRotationWeekAuditHistoryAsync( .OrderByDescending(a => a.TimeStamp) .ToListAsync(cancellationToken); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving audit history for rotation {RotationId}, week {WeekId}", rotationId, weekId); throw new InvalidOperationException($"Failed to retrieve audit history for rotation {rotationId}, week {weekId}. Please try again or contact support if the problem persists.", ex); @@ -180,7 +180,7 @@ private async Task CreateAuditEntryAsync( return auditEntry; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error creating audit entry for action {Action}, {MothraId} on rotation {RotationId}, week {WeekId}", action, LogSanitizer.SanitizeId(mothraId), rotationId, weekId); diff --git a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs index b2e20e646..c8faa7dbd 100644 --- a/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs +++ b/web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs @@ -241,7 +241,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( // Re-throw InvalidOperationException without wrapping (includes "already scheduled" messages) throw; } - catch (Exception saveEx) when (saveEx is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception saveEx) when (saveEx is DbUpdateException or SqlException) { _logger.LogError(saveEx, "Database save failed for MothraId='{MothraId}', RotationId={RotationId}, WeekIds=[{WeekIds}]", LogSanitizer.SanitizeId(mothraId), rotationId, string.Join(",", weekIds)); @@ -359,7 +359,7 @@ await _auditService.LogInstructorRemovedAsync( // Re-throw InvalidOperationException without wrapping (includes "Cannot remove primary evaluator" message) throw; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException) { _logger.LogError(ex, "Error removing instructor schedule {ScheduleId}", instructorScheduleId); throw new InvalidOperationException($"Failed to remove instructor schedule. Please try again or contact support if the problem persists.", ex); @@ -470,7 +470,7 @@ await _auditService.LogPrimaryEvaluatorSetAsync( return (true, previousPrimaryName); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error setting primary evaluator for instructor schedule {ScheduleId} to {IsPrimary}", instructorScheduleId, isPrimary); throw new InvalidOperationException($"Failed to update primary evaluator status. Please try again or contact support if the problem persists.", ex); @@ -495,7 +495,7 @@ public async Task CanRemoveInstructorAsync( // All instructors can now be removed, including primary evaluators return true; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error checking if instructor schedule {ScheduleId} can be removed", instructorScheduleId); return false; @@ -537,7 +537,7 @@ public async Task> GetOtherRotationSchedulesAsync( return await query.ToListAsync(cancellationToken); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error checking other rotation schedules for {MothraId} on weeks {WeekIds} for grad year {GradYear}", LogSanitizer.SanitizeId(mothraId), string.Join(",", weekIds), LogSanitizer.SanitizeYear(gradYear)); @@ -565,7 +565,7 @@ public async Task> GetScheduledInstructorsAsync( .Where(s => s.RotationId == rotationId && weekIds.Contains(s.WeekId)) .ToListAsync(cancellationToken); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error getting scheduled instructors for rotation {RotationId} on weeks {WeekIds}", rotationId, string.Join(",", weekIds)); throw new InvalidOperationException($"Failed to retrieve scheduled instructors. Please try again or contact support if the problem persists.", ex); @@ -668,7 +668,7 @@ private async Task SendPrimaryEvaluatorRemovedNotificationAsync(InstructorSchedu } } } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogWarning(ex, "Could not retrieve instructor name for {MothraId} in email notification", LogSanitizer.SanitizeId(schedule.MothraId)); } @@ -701,7 +701,7 @@ await _context.Entry(schedule) weekNumber = weekGradYear.WeekNum.ToString(); } } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogWarning(ex, "Could not retrieve week number for {WeekId} in email notification", schedule.WeekId); } @@ -726,7 +726,7 @@ await _context.Entry(schedule) : ""; } } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogWarning(ex, "Could not retrieve modifier information for {MothraId} in email notification", modifiedByMothraId); } diff --git a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs index 9c08550c0..1cc46970f 100644 --- a/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs +++ b/web/Areas/ClinicalScheduler/Services/SchedulePermissionService.cs @@ -88,7 +88,7 @@ public async Task HasEditPermissionForServiceAsync(int serviceId, Cancella return hasPermission; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var currentUser = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and service {ServiceId}", LogSanitizer.SanitizeId(currentUser?.MothraId), serviceId); @@ -115,7 +115,7 @@ public async Task HasEditPermissionForRotationAsync(int rotationId, Cancel return await HasEditPermissionForServiceAsync(rotation.ServiceId, cancellationToken); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking edit permissions for user {MothraId} and rotation {RotationId}", LogSanitizer.SanitizeId(user?.MothraId), rotationId); @@ -151,7 +151,7 @@ public async Task> GetUserEditableServicesAsync(CancellationToken return editableServices; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting editable services for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -184,7 +184,7 @@ public async Task> GetUserServicePermissionsAsync(Cancella return permissions; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error getting service permissions for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -213,7 +213,7 @@ public async Task GetRequiredPermissionForServiceAsync(int serviceId, Ca _logger.LogDebug("Required permission for service {ServiceId}: {RequiredPermission}", serviceId, requiredPermission); return requiredPermission; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error getting required permission for service {ServiceId}", serviceId); return ClinicalSchedulePermissions.Manage; @@ -259,7 +259,7 @@ public async Task CanEditOwnScheduleAsync(int instructorScheduleId, Cancel return canEdit; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking own schedule permissions for user {MothraId} and instructor schedule {InstructorScheduleId}", @@ -305,7 +305,7 @@ public Task CheckStudentScheduleParamsAsync(string? mothraId, int? rotatio _logger.LogDebug("User {MothraId} denied access to student schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking student schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); @@ -347,7 +347,7 @@ public Task CheckInstructorScheduleParamsAsync(string? mothraId, int? rota _logger.LogDebug("User {MothraId} denied access to instructor schedules", LogSanitizer.SanitizeId(user.MothraId)); return Task.FromResult(false); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { var user = _userHelper.GetCurrentUser(); _logger.LogError(ex, "Error checking instructor schedule access for user {MothraId}", LogSanitizer.SanitizeId(user?.MothraId)); diff --git a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs index 1ea6f8044..67d1c7795 100644 --- a/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs +++ b/web/Areas/ClinicalScheduler/Services/StudentScheduleService.cs @@ -111,7 +111,7 @@ public async Task> GetStudentScheduleAsync( _logger.LogInformation("Found {Count} student schedules", result.Count); return result; } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving student schedules"); throw new InvalidOperationException("Failed to retrieve student schedules", ex); diff --git a/web/Areas/ClinicalScheduler/Services/WeekService.cs b/web/Areas/ClinicalScheduler/Services/WeekService.cs index f34078f54..efd0450a4 100644 --- a/web/Areas/ClinicalScheduler/Services/WeekService.cs +++ b/web/Areas/ClinicalScheduler/Services/WeekService.cs @@ -49,7 +49,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weeks.Count, gradYear, includeExtendedRotation); return weeks.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving weeks for grad year {GradYear}: {ErrorMessage}", gradYear, ex.Message); throw new InvalidOperationException($"Failed to retrieve weeks for graduation year {gradYear}", ex); @@ -90,7 +90,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende weekId, week.GradYear, week.WeekNum); return week.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving week {WeekId} for grad year {GradYear}", weekId, gradYear); throw new InvalidOperationException($"Failed to retrieve week {weekId} for graduation year {gradYear}", ex); @@ -131,7 +131,7 @@ public async Task> GetWeeksAsync(int gradYear, bool includeExtende _logger.LogInformation("Current week is {WeekNum} for grad year {GradYear}", week.WeekNum, week.GradYear); return week.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving current week for grad year {GradYear}", gradYear); throw new InvalidOperationException($"Failed to retrieve current week for graduation year {gradYear}", ex); @@ -175,7 +175,7 @@ public async Task> GetWeeksByDateRangeAsync(DateTime? startDate = weeks.Count, startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none"); return weeks.ToDto(); } - catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException or OperationCanceledException) + catch (Exception ex) when (ex is DbUpdateException or SqlException or InvalidOperationException) { _logger.LogError(ex, "Error retrieving weeks for date range {StartDate} to {EndDate}", startDate?.ToString("yyyy-MM-dd") ?? "none", endDate?.ToString("yyyy-MM-dd") ?? "none");