Refactor SQL exception handling and config structure

Simplify SQL exception tracking by replacing error message mappings
with a list of relevant error numbers in appsettings.json. Remove
custom error message logic and related classes, introducing
SqlExceptionOptions to hold tracked error codes.
This commit is contained in:
Developer 02
2026-01-22 01:45:50 +01:00
parent ed7237c8dd
commit 22bb585f60
4 changed files with 8 additions and 89 deletions

View File

@@ -10,10 +10,8 @@
}, },
"SqlExceptionTranslator": { "SqlExceptionTranslator": {
"ErrorMessages": { "ErrorMessages": {
"515": "{Operation} '{Target}' failed because a required field was not provided or was null. Verify mandatory values and retry.", // https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlexception.number
"547": "{Operation} '{Target}' failed because one or more referenced entities do not exist or violate relational rules. Please verify identifiers and constraints.", "SqlExceptionNumber": [ 515 , 547, 2601, 2627]
"2601": "{Operation} '{Target}' failed because the data conflicts with a unique constraint. Remove duplicate values and retry.",
"2627": "{Operation} '{Target}' failed because the data conflicts with a unique constraint. Remove duplicate values and retry."
} }
}, },
"AddedWho": "ReC.API", "AddedWho": "ReC.API",

View File

@@ -0,0 +1,6 @@
namespace ReC.Application.Common.Options;
public class SqlExceptionOptions
{
public HashSet<int> SqlExceptionNumber { get; set; } = [];
}

View File

@@ -1,24 +0,0 @@
namespace ReC.Application.Common.Options;
public class SqlExceptionTranslatorOptions
{
public HashSet<int> ErrorNumbers { get; private set; } = [];
private Dictionary<int, string> _badRequestMessages = new()
{
[515] = "{Operation} '{Target}' failed because a required field was not provided or was null. Verify mandatory values and retry.",
[547] = "{Operation} '{Target}' failed because one or more referenced entities do not exist or violate relational rules. Please verify identifiers and constraints.",
[2601] = "{Operation} '{Target}' failed because the data conflicts with a unique constraint. Remove duplicate values and retry.",
[2627] = "{Operation} '{Target}' failed because the data conflicts with a unique constraint. Remove duplicate values and retry."
};
public Dictionary<int, string> ErrorMessages
{
get => _badRequestMessages;
set
{
_badRequestMessages = value;
ErrorNumbers = [.. value.Keys];
}
}
}

View File

@@ -1,61 +0,0 @@
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using ReC.Application.Common.Options;
namespace ReC.Application.Common.Procedures;
internal interface ISqlExceptionTranslator
{
bool IsBadRequestDataIssue(SqlException exception);
string BuildBadRequestMessage(string operation, string? entity, SqlException exception);
}
internal sealed class SqlExceptionTranslator : ISqlExceptionTranslator
{
private readonly IOptionsMonitor<SqlExceptionTranslatorOptions> _optionsMonitor;
public SqlExceptionTranslator(IOptionsMonitor<SqlExceptionTranslatorOptions> optionsMonitor)
{
_optionsMonitor = optionsMonitor;
}
public bool IsBadRequestDataIssue(SqlException exception)
{
var options = _optionsMonitor.CurrentValue;
if (options.BadRequestErrorNumbers is { Count: > 0 } &&
options.BadRequestErrorNumbers.Contains(exception.Number))
{
return true;
}
return options.BadRequestMessages?.ContainsKey(exception.Number) ?? false;
}
public string BuildBadRequestMessage(string operation, string? entity, SqlException exception)
{
var target = string.IsNullOrWhiteSpace(entity) ? "object" : entity;
var options = _optionsMonitor.CurrentValue;
var template = ResolveTemplate(options, exception.Number);
return template
.Replace("{Operation}", operation)
.Replace("{Target}", target)
.Replace("{ErrorMessage}", exception.Message);
}
private static string ResolveTemplate(SqlExceptionTranslatorOptions options, int errorNumber)
{
if (options.BadRequestMessages is not null &&
options.BadRequestMessages.TryGetValue(errorNumber, out var template) &&
!string.IsNullOrWhiteSpace(template))
{
return template;
}
return string.IsNullOrWhiteSpace(options.DefaultBadRequestMessage)
? SqlExceptionTranslatorOptions.DefaultFallbackMessage
: options.DefaultBadRequestMessage;
}
}