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:
@@ -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",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace ReC.Application.Common.Options;
|
||||||
|
|
||||||
|
public class SqlExceptionOptions
|
||||||
|
{
|
||||||
|
public HashSet<int> SqlExceptionNumber { get; set; } = [];
|
||||||
|
}
|
||||||
@@ -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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user