fix(backend): sanitize exception disclosure in changed API endpoints

Replace raw exception-message disclosure (ex.Message) returned to API
callers with a stable sanitized public message plus correlated structured
internal logging, across the endpoints changed in this PR.

- Add SanitizedErrors helper: logs the original exception at Error with a
  generated correlation id and returns a stable public message referencing
  it so support can trace without exposing internals.
- Inject ILogger<T> into the 14 changed controllers and route every
  ex.Message/dbex.Message disclosure through the helper, preserving status
  codes, response shapes, and business data (e.g. OpenWorkOrders).
- Leave FluentValidation (vex.Errors) and existing fixed-message catches
  untouched; out-of-scope controllers (Account/Contact/Employee/Asset/
  PMSchedule) are unchanged.
- Add focused tests proving internal exception text is not returned and
  that Error logging carrying the original exception is invoked.
This commit is contained in:
Alexandre Brandizzi 2026-07-24 14:14:39 -03:00
parent 6f6c7e04cd
commit 32de36f78c
26 changed files with 386 additions and 99 deletions

View file

@ -4,6 +4,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -20,7 +21,7 @@ public class AuthenticationControllerTests
private static AuthenticationController NewController(Mock<IAuthenticationService> service, string? userId = null)
{
var controller = new AuthenticationController(service.Object);
var controller = new AuthenticationController(service.Object, Mock.Of<ILogger<AuthenticationController>>());
if (userId != null)
{
controller.ControllerContext = new ControllerContext
@ -82,6 +83,35 @@ public class AuthenticationControllerTests
result.Should().BeOfType<UnauthorizedResult>();
}
[Fact]
public async Task Login_WhenServiceThrows_ReturnsSanitized500AndLogsInternally()
{
var service = new Mock<IAuthenticationService>();
service.Setup(s => s.LoginAsync(It.IsAny<string?>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new InvalidOperationException("SECRET-internal-stack-detail"));
var logger = new Mock<ILogger<AuthenticationController>>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var controller = new AuthenticationController(service.Object, logger.Object);
var result = await controller.Login(new LoginModel { Username = "x", Password = "y" }, CancellationToken.None);
var status = result.Should().BeOfType<ObjectResult>().Subject;
status.StatusCode.Should().Be(500);
var message = (string)status.Value!;
message.Should().NotContain("SECRET");
message.Should().NotContain("internal-stack-detail");
message.Should().Contain("reference");
logger.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.Is<Exception>(ex => ex.Message.Contains("SECRET")),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
[Fact]
public async Task ChangePassword_Success_ReturnsSuccessMessageWithTrailingSpace()
{

View file

@ -4,6 +4,7 @@ using Api.SeaHavenIndustries.DTOs;
using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -26,7 +27,7 @@ public class CalendarControllerTests
};
private static CalendarController NewController(Mock<ICalendarService> service) =>
new(service.Object);
new(service.Object, Mock.Of<ILogger<CalendarController>>());
private static object Prop(object source, string name) =>
source.GetType().GetProperty(name)!.GetValue(source)!;
@ -45,17 +46,32 @@ public class CalendarControllerTests
}
[Fact]
public async Task AddEvent_WhenServiceThrows_ReturnsBadRequestWithMessage()
public async Task AddEvent_WhenServiceThrows_ReturnsSanitizedMessageAndLogsInternally()
{
var service = new Mock<ICalendarService>();
service.Setup(s => s.CreateEventAsync(It.IsAny<EditEventInput>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new InvalidOperationException("boom"));
.ThrowsAsync(new InvalidOperationException("SECRET-internal-db-connection-leak"));
var result = await NewController(service).AddEvent(ValidDto(), CancellationToken.None);
var logger = new Mock<ILogger<CalendarController>>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var controller = new CalendarController(service.Object, logger.Object);
var result = await controller.AddEvent(ValidDto(), CancellationToken.None);
var bad = result.Should().BeOfType<BadRequestObjectResult>().Subject;
var response = bad.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().Be("boom");
response.Status.Should().Be("Error");
response.Message.Should().NotContain("SECRET");
response.Message.Should().NotContain("internal-db-connection-leak");
response.Message.Should().Contain("reference");
logger.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.Is<Exception>(ex => ex.Message.Contains("SECRET")),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
[Fact]

View file

@ -5,6 +5,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -16,7 +17,7 @@ public class FollowUpControllerTests
{
private static FollowUpController NewController(Mock<IFollowUpService> service)
{
var controller = new FollowUpController(service.Object)
var controller = new FollowUpController(service.Object, Mock.Of<ILogger<FollowUpController>>())
{
ControllerContext = new ControllerContext
{
@ -33,7 +34,7 @@ public class FollowUpControllerTests
}
private static FollowUpController NewControllerNoUser(Mock<IFollowUpService> service) =>
new(service.Object)
new(service.Object, Mock.Of<ILogger<FollowUpController>>())
{
ControllerContext = new ControllerContext
{

View file

@ -4,6 +4,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -14,7 +15,7 @@ namespace Api.SeaHavenIndustries.Tests;
public class LocationControllerTests
{
private static LocationController NewController(Mock<ILocationService> service) =>
new(service.Object);
new(service.Object, Mock.Of<ILogger<LocationController>>());
private static object Prop(object source, string name) =>
source.GetType().GetProperty(name)!.GetValue(source)!;

View file

@ -0,0 +1,71 @@
using Api.SeaHavenIndustries.Helper;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace Api.SeaHavenIndustries.Tests;
public class SanitizedErrorsTests
{
[Fact]
public void Sanitize_ReturnsStableMessageAndNeverExposesExceptionText()
{
var logger = new Mock<ILogger>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var message = logger.Object.Sanitize(new InvalidOperationException("SUPER-SECRET-internal-detail"));
message.Should().NotContain("SUPER-SECRET");
message.Should().NotContain("internal-detail");
message.Should().StartWith("An unexpected error occurred");
message.Should().Contain("reference");
}
[Fact]
public void Sanitize_UsesProvidedPublicMessageInsteadOfExceptionText()
{
var logger = new Mock<ILogger>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var message = logger.Object.Sanitize(
new InvalidOperationException("SUPER-SECRET-internal-detail"),
"Vendor not found");
message.Should().Contain("Vendor not found");
message.Should().NotContain("SUPER-SECRET");
message.Should().Contain("reference");
}
[Fact]
public void Sanitize_LogsOriginalExceptionAtErrorLevel()
{
var logger = new Mock<ILogger>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var exception = new InvalidOperationException("SUPER-SECRET-internal-detail");
logger.Object.Sanitize(exception);
logger.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.Is<Exception>(ex => ex == exception),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
[Fact]
public void Sanitize_ProducesUniqueCorrelationReferencesAcrossCalls()
{
var logger = new Mock<ILogger>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var exception = new InvalidOperationException("detail");
var first = logger.Object.Sanitize(exception);
var second = logger.Object.Sanitize(exception);
first.Should().NotBe(second);
}
}

View file

@ -4,6 +4,7 @@ using Api.SeaHavenIndustries.Helper.ViewModel;
using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -14,7 +15,7 @@ namespace Api.SeaHavenIndustries.Tests;
public class SettingsControllerTests
{
private static SettingsController NewController(Mock<ISettingsService> service) =>
new(service.Object);
new(service.Object, Mock.Of<ILogger<SettingsController>>());
[Fact]
public async Task GetCategoryList_ReturnsPaginationEnvelopeWithServiceItems()

View file

@ -3,6 +3,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -15,7 +16,7 @@ public class UpliftControllerTests
{
private static UpliftController NewController(Mock<IUpliftService> service, params string[] roles)
{
var controller = new UpliftController(service.Object);
var controller = new UpliftController(service.Object, Mock.Of<ILogger<UpliftController>>());
var claims = new List<Claim> { new(ClaimTypes.NameIdentifier, "42") };
claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
controller.ControllerContext = new ControllerContext
@ -66,6 +67,41 @@ public class UpliftControllerTests
nf.Value.Should().BeOfType<Response>();
}
[Fact]
public async Task Approve_Forbidden_ReturnsSanitized403AndLogsInternally()
{
var service = new Mock<IUpliftService>();
service.Setup(x => x.ApproveAsync(It.IsAny<ClaimsPrincipal>(), 5, null, It.IsAny<CancellationToken>()))
.ThrowsAsync(new UpliftForbiddenException("SECRET-tier-restriction-detail"));
var logger = new Mock<ILogger<UpliftController>>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var controller = new UpliftController(service.Object, logger.Object);
controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "42") }, "Test"))
}
};
var result = await controller.Approve(5, null);
var status = result.Should().BeOfType<ObjectResult>().Subject;
status.StatusCode.Should().Be(403);
var response = status.Value.Should().BeOfType<Response>().Subject;
response.Message.Should().NotContain("SECRET");
response.Message.Should().Contain("reference");
logger.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.Is<Exception>(ex => ex.Message.Contains("SECRET")),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
[Fact]
public async Task Approve_ForbiddenTier_Returns403()
{

View file

@ -4,6 +4,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -20,7 +21,7 @@ public class UserControllerTests
private static UserController NewController(Mock<IUserService> service, string? userId = null)
{
var controller = new UserController(service.Object);
var controller = new UserController(service.Object, Mock.Of<ILogger<UserController>>());
if (userId != null)
{
controller.ControllerContext = new ControllerContext

View file

@ -4,6 +4,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -16,7 +17,7 @@ public class VendorControllerTests
{
private static VendorController NewController(Mock<IVendorService> service)
{
var controller = new VendorController(service.Object);
var controller = new VendorController(service.Object, Mock.Of<ILogger<VendorController>>());
controller.ControllerContext = new ControllerContext
{
@ -218,6 +219,44 @@ public class VendorControllerTests
result.Should().BeOfType<NotFoundResult>();
}
[Fact]
public async Task Delete_WhenDeactivationBlocked_ReturnsSanitizedConflictWithOpenWorkOrdersAndLogs()
{
var openWorkOrders = new List<LinkedWorkOrderDTO> { new() { WorkOrderId = 7 } };
var service = new Mock<IVendorService>();
service.Setup(x => x.DeleteVendorAsync(It.IsAny<int>(), It.IsAny<string>()))
.ThrowsAsync(new VendorDeactivationBlockedException("SECRET-internal-reason", openWorkOrders));
var logger = new Mock<ILogger<VendorController>>();
logger.Setup(x => x.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
var controller = new VendorController(service.Object, logger.Object);
controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "42") }, "Test"))
}
};
var result = await controller.Delete(5);
var conflict = result.Should().BeOfType<ConflictObjectResult>().Subject;
var value = conflict.Value!;
var message = (string)value.GetType().GetProperty("Message")!.GetValue(value)!;
message.Should().NotContain("SECRET");
message.Should().Contain("reference");
var returnedOpenWorkOrders = (List<LinkedWorkOrderDTO>)value.GetType().GetProperty("OpenWorkOrders")!.GetValue(value)!;
returnedOpenWorkOrders.Should().HaveCount(1);
logger.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.Is<Exception>(ex => ex.Message.Contains("SECRET")),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Once);
}
[Fact]
public async Task Delete_MapsDeactivationBlocked_ToConflict()
{
@ -265,7 +304,7 @@ public class VendorControllerTests
public async Task Update_UnauthenticatedUser_ReturnsUnauthorized()
{
var service = new Mock<IVendorService>();
var controller = new VendorController(service.Object);
var controller = new VendorController(service.Object, Mock.Of<ILogger<VendorController>>());
controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal() }

View file

@ -3,6 +3,7 @@ using Data.SeaHavenIndustries;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Moq;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -14,7 +15,7 @@ public class VendorPortalControllerTests
{
private static VendorPortalController NewController(Mock<IVendorPortalService> service, string? token = "valid-token")
{
var controller = new VendorPortalController(service.Object);
var controller = new VendorPortalController(service.Object, Mock.Of<ILogger<VendorPortalController>>());
var context = new DefaultHttpContext();
if (token != null)
context.Request.Headers["X-Vendor-Token"] = token;
@ -133,7 +134,8 @@ public class VendorPortalControllerTests
var bad = result.Should().BeOfType<BadRequestObjectResult>().Subject;
var resp = bad.Value.Should().BeOfType<Response>().Subject;
resp.Message.Should().Be("Cannot accept");
resp.Message.Should().NotContain("Cannot accept");
resp.Message.Should().Contain("reference");
}
[Fact]
@ -169,7 +171,8 @@ public class VendorPortalControllerTests
var bad = result.Should().BeOfType<BadRequestObjectResult>().Subject;
var resp = bad.Value.Should().BeOfType<Response>().Subject;
resp.Message.Should().Contain("Transition");
resp.Message.Should().NotContain("Transition");
resp.Message.Should().Contain("reference");
}
[Fact]

View file

@ -24,4 +24,8 @@
<ProjectReference Include="..\SeaHaven.DataServices\SeaHaven.DataServices.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Api.SeaHavenIndustries.Tests" />
</ItemGroup>
</Project>

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
using System.Security.Claims;
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class AuthenticationController : Controller
{
private readonly IAuthenticationService _authenticationService;
private readonly ILogger<AuthenticationController> _logger;
public AuthenticationController(IAuthenticationService authenticationService)
public AuthenticationController(IAuthenticationService authenticationService, ILogger<AuthenticationController> logger)
{
_authenticationService = authenticationService;
_logger = logger;
}
[AllowAnonymous]
@ -46,7 +50,7 @@ namespace Api.SeaHavenIndustries.Controllers
catch (Exception ex)
{
return StatusCode(500, ex.Message);
return StatusCode(500, _logger.Sanitize(ex));
}
}
@ -94,7 +98,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -135,7 +139,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = "Error: " + ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -159,7 +163,7 @@ namespace Api.SeaHavenIndustries.Controllers
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = "Error: " + ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class CalendarController : Controller
{
private readonly ICalendarService _calendarService;
private readonly ILogger<CalendarController> _logger;
public CalendarController(ICalendarService calendarService)
public CalendarController(ICalendarService calendarService, ILogger<CalendarController> logger)
{
_calendarService = calendarService;
_logger = logger;
}
// ===================================================================================
@ -34,7 +38,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -62,7 +66,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -86,7 +90,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -109,7 +113,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -135,7 +139,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -154,7 +158,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Api.SeaHavenIndustries.Helper.ViewModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.Interfaces;
namespace Api.SeaHavenIndustries.Controllers
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class CommonController : Controller
{
private readonly ICommonService _commonService;
private readonly ILogger<CommonController> _logger;
public CommonController(ICommonService commonService)
public CommonController(ICommonService commonService, ILogger<CommonController> logger)
{
_commonService = commonService;
_logger = logger;
}
[HttpGet]
@ -49,7 +53,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new { Status = "Error", Message = ex.Message });
return BadRequest(new { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -65,7 +69,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new { Status = "Error", Message = ex.Message });
return BadRequest(new { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,6 +1,8 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -12,10 +14,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class DropdownOptionsController : Controller
{
private readonly IDropdownOptionsService _dropdownOptionsService;
private readonly ILogger<DropdownOptionsController> _logger;
public DropdownOptionsController(IDropdownOptionsService dropdownOptionsService)
public DropdownOptionsController(IDropdownOptionsService dropdownOptionsService, ILogger<DropdownOptionsController> logger)
{
_dropdownOptionsService = dropdownOptionsService;
_logger = logger;
}
[HttpGet]
@ -42,7 +46,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new { message = ex.Message });
return BadRequest(new { message = _logger.Sanitize(ex, "The dropdown option could not be saved") });
}
}

View file

@ -1,9 +1,11 @@
using System.Security.Claims;
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -14,10 +16,12 @@ using SeaHaven.Services.Interfaces;
public class FollowUpController : ControllerBase
{
private readonly IFollowUpService _followUpService;
private readonly ILogger<FollowUpController> _logger;
public FollowUpController(IFollowUpService followUpService)
public FollowUpController(IFollowUpService followUpService, ILogger<FollowUpController> logger)
{
_followUpService = followUpService;
_logger = logger;
}
[HttpGet("GetFollowUpList")]
@ -111,7 +115,7 @@ public class FollowUpController : ControllerBase
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -134,7 +138,7 @@ public class FollowUpController : ControllerBase
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -173,7 +177,7 @@ public class FollowUpController : ControllerBase
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,8 +1,10 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -15,10 +17,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class LocationController : Controller
{
private readonly ILocationService _locationService;
private readonly ILogger<LocationController> _logger;
public LocationController(ILocationService locationService)
public LocationController(ILocationService locationService, ILogger<LocationController> logger)
{
_locationService = locationService;
_logger = logger;
}
[HttpGet("GetLocationList")]
@ -98,7 +102,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -121,7 +125,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -142,7 +146,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class QuotesController : Controller
{
private readonly IQuotesService _quotesService;
private readonly ILogger<QuotesController> _logger;
public QuotesController(IQuotesService quotesService)
public QuotesController(IQuotesService quotesService, ILogger<QuotesController> logger)
{
_quotesService = quotesService;
_logger = logger;
}
[HttpPost]
@ -31,7 +35,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -49,7 +53,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -68,7 +72,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,8 +1,10 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Api.SeaHavenIndustries.Helper.ViewModel;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.Interfaces;
namespace Api.SeaHavenIndustries.Controllers
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class SettingsController : Controller
{
private readonly ISettingsService _settingsService;
private readonly ILogger<SettingsController> _logger;
public SettingsController(ISettingsService settingsService)
public SettingsController(ISettingsService settingsService, ILogger<SettingsController> logger)
{
_settingsService = settingsService;
_logger = logger;
}
[HttpPost]
@ -30,7 +34,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -47,7 +51,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -64,7 +68,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -109,7 +113,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -145,7 +149,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new { Status = "Error", Message = ex.Message });
return BadRequest(new { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -161,7 +165,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
}

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -14,10 +16,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class TaskListTemplateController : Controller
{
private readonly ITaskListTemplateService _taskListTemplateService;
private readonly ILogger<TaskListTemplateController> _logger;
public TaskListTemplateController(ITaskListTemplateService taskListTemplateService)
public TaskListTemplateController(ITaskListTemplateService taskListTemplateService, ILogger<TaskListTemplateController> logger)
{
_taskListTemplateService = taskListTemplateService;
_logger = logger;
}
[HttpGet]
@ -49,7 +53,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -67,7 +71,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,6 +1,8 @@
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class UpliftController : Controller
{
private readonly IUpliftService _upliftService;
private readonly ILogger<UpliftController> _logger;
public UpliftController(IUpliftService upliftService)
public UpliftController(IUpliftService upliftService, ILogger<UpliftController> logger)
{
_upliftService = upliftService;
_logger = logger;
}
[HttpGet]
@ -43,15 +47,15 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (KeyNotFoundException ex)
{
return NotFound(new Response { Status = "Error", Message = ex.Message });
return NotFound(new Response { Status = "Error", Message = _logger.Sanitize(ex, "Uplift request not found") });
}
catch (UpliftForbiddenException ex)
{
return StatusCode(403, new Response { Status = "Error", Message = ex.Message });
return StatusCode(403, new Response { Status = "Error", Message = _logger.Sanitize(ex, "You are not authorized to perform this action on this uplift request") });
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "This uplift request cannot be modified in its current state") });
}
}
@ -65,15 +69,15 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (KeyNotFoundException ex)
{
return NotFound(new Response { Status = "Error", Message = ex.Message });
return NotFound(new Response { Status = "Error", Message = _logger.Sanitize(ex, "Uplift request not found") });
}
catch (UpliftForbiddenException ex)
{
return StatusCode(403, new Response { Status = "Error", Message = ex.Message });
return StatusCode(403, new Response { Status = "Error", Message = _logger.Sanitize(ex, "You are not authorized to perform this action on this uplift request") });
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "This uplift request cannot be modified in its current state") });
}
}

View file

@ -1,7 +1,9 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
using System.Security.Claims;
@ -14,10 +16,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class UserController : Controller
{
private readonly IUserService _userService;
private readonly ILogger<UserController> _logger;
public UserController(IUserService userService)
public UserController(IUserService userService, ILogger<UserController> logger)
{
_userService = userService;
_logger = logger;
}
[Route("")]
[HttpGet]
@ -49,7 +53,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -73,7 +77,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -93,7 +97,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -109,7 +113,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,8 +1,10 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.Interfaces;
using SeaHaven.Services.DTOs;
using System.Security.Claims;
@ -16,10 +18,12 @@ namespace Api.SeaHavenIndustries.Controllers
public class VendorController : Controller
{
private readonly IVendorService _vendorService;
private readonly ILogger<VendorController> _logger;
public VendorController(IVendorService vendorService)
public VendorController(IVendorService vendorService, ILogger<VendorController> logger)
{
_vendorService = vendorService;
_logger = logger;
}
[HttpGet("GetVendorList")]
@ -148,7 +152,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -199,7 +203,7 @@ namespace Api.SeaHavenIndustries.Controllers
return Conflict(new
{
Status = "Conflict",
Message = dbex.Message,
Message = _logger.Sanitize(dbex, "Vendor cannot be deactivated because it has open work orders"),
OpenWorkOrders = dbex.OpenWorkOrders
});
}
@ -209,7 +213,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -236,7 +240,7 @@ namespace Api.SeaHavenIndustries.Controllers
return Conflict(new
{
Status = "Conflict",
Message = dbex.Message,
Message = _logger.Sanitize(dbex, "Vendor cannot be deactivated because it has open work orders"),
OpenWorkOrders = dbex.OpenWorkOrders
});
}
@ -246,7 +250,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -264,7 +268,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -304,7 +308,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return StatusCode(500, new Response { Status = "Error", Message = ex.Message });
return StatusCode(500, new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -1,5 +1,7 @@
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
@ -13,10 +15,12 @@ namespace Api.SeaHavenIndustries.Controllers
private const string TokenHeader = "X-Vendor-Token";
private readonly IVendorPortalService _portalService;
private readonly ILogger<VendorPortalController> _logger;
public VendorPortalController(IVendorPortalService portalService)
public VendorPortalController(IVendorPortalService portalService, ILogger<VendorPortalController> logger)
{
_portalService = portalService;
_logger = logger;
}
[HttpGet("session")]
@ -71,7 +75,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -92,7 +96,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -113,7 +117,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -134,7 +138,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -155,7 +159,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -176,7 +180,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -197,7 +201,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}
@ -218,7 +222,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The requested action could not be completed for this dispatch") });
}
}

View file

@ -1,8 +1,10 @@
using Api.SeaHavenIndustries.DTOs;
using Api.SeaHavenIndustries.Helper;
using Data.SeaHavenIndustries;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SeaHaven.Services.DTOs;
using SeaHaven.Services.Interfaces;
using SeaHaven.DataServices.Models;
@ -18,13 +20,16 @@ namespace Api.SeaHavenIndustries.Controllers
{
private readonly IWorkOrderService _workOrderService;
private readonly IWorkOrderDispatchService _dispatchService;
private readonly ILogger<WorkOrderController> _logger;
public WorkOrderController(
IWorkOrderService workOrderService,
IWorkOrderDispatchService dispatchService)
IWorkOrderDispatchService dispatchService,
ILogger<WorkOrderController> logger)
{
_workOrderService = workOrderService;
_dispatchService = dispatchService;
_logger = logger;
}
[HttpPost]
@ -60,7 +65,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -107,7 +112,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -149,7 +154,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -238,7 +243,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -257,7 +262,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -281,7 +286,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -304,7 +309,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -365,7 +370,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -410,7 +415,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -436,7 +441,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -458,7 +463,7 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}
@ -484,11 +489,11 @@ namespace Api.SeaHavenIndustries.Controllers
}
catch (InvalidOperationException ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex, "The dispatch signoff could not be added") });
}
catch (Exception ex)
{
return BadRequest(new Response { Status = "Error", Message = ex.Message });
return BadRequest(new Response { Status = "Error", Message = _logger.Sanitize(ex) });
}
}

View file

@ -0,0 +1,27 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Logging;
namespace Api.SeaHavenIndustries.Helper;
internal static class SanitizedErrors
{
private const string DefaultPublicMessage = "An unexpected error occurred";
public static string Sanitize(
this ILogger logger,
Exception exception,
string? publicMessage = null,
[CallerMemberName] string operation = "")
{
var correlationId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
logger.LogError(
exception,
"Unhandled exception in {Operation}. CorrelationId: {CorrelationId}",
operation,
correlationId);
return $"{publicMessage ?? DefaultPublicMessage} (reference {correlationId}).";
}
}