using System.Data; using System.Diagnostics; using Microsoft.Data.SqlClient; namespace Gateway.Data; public class SqlService { private readonly IConfiguration _config; private readonly ILogger _logger; public SqlService(IConfiguration config, ILogger logger) { _config = config; _logger = logger; } private string GetConnectionString() { // expects env var: ConnectionStrings__Sql var cs = _config.GetConnectionString("Sql"); if (string.IsNullOrWhiteSpace(cs)) throw new InvalidOperationException("Missing connection string: ConnectionStrings:Sql (env var ConnectionStrings__Sql)."); return cs; } /// /// Executes a stored procedure using the standard signature: /// @action varchar(..), /// @rqst nvarchar(max), /// @resp nvarchar(max) OUTPUT /// Returns the output JSON string (resp). /// public async Task ExecProcAsync( string procName, string action, string rqstJson, int commandTimeoutSeconds = 60, CancellationToken ct = default) { if (string.IsNullOrWhiteSpace(procName)) throw new ArgumentException("procName is required.", nameof(procName)); if (string.IsNullOrWhiteSpace(action)) throw new ArgumentException("action is required.", nameof(action)); if (string.IsNullOrWhiteSpace(rqstJson)) rqstJson = "{}"; var sw = Stopwatch.StartNew(); try { await using var conn = new SqlConnection(GetConnectionString()); await conn.OpenAsync(ct); await using var cmd = new SqlCommand(procName, conn) { CommandType = CommandType.StoredProcedure, CommandTimeout = commandTimeoutSeconds }; cmd.Parameters.Add(new SqlParameter("@action", SqlDbType.VarChar, 50) { Value = action }); cmd.Parameters.Add(new SqlParameter("@rqst", SqlDbType.NVarChar, -1) { Value = rqstJson }); var pResp = new SqlParameter("@resp", SqlDbType.NVarChar, -1) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(pResp); await cmd.ExecuteNonQueryAsync(ct); var resp = pResp.Value as string ?? ""; sw.Stop(); _logger.LogInformation("SQL ok: {Proc} action={Action} ms={Ms}", procName, action, sw.ElapsedMilliseconds); return resp; } catch (SqlException ex) { sw.Stop(); _logger.LogError(ex, "SQL error: {Proc} action={Action} ms={Ms}", procName, action, sw.ElapsedMilliseconds); throw; } catch (Exception ex) { sw.Stop(); _logger.LogError(ex, "App error calling SQL: {Proc} action={Action} ms={Ms}", procName, action, sw.ElapsedMilliseconds); throw; } } }