Add error handling for permission API calls and enhance logging in middleware
All checks were successful
Build & Deploy Leave Service / build (push) Successful in 1m15s

This commit is contained in:
Suphonchai Phoonsawat 2026-01-22 11:58:26 +07:00
parent d3501e831c
commit d945deae4f
3 changed files with 72 additions and 40 deletions

View file

@ -62,6 +62,10 @@ namespace BMA.EHR.Application.Repositories
new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
client.DefaultRequestHeaders.Add("api-key", _configuration["API_KEY"]);
var req = await client.GetAsync(apiPath);
if (!req.IsSuccessStatusCode)
{
throw new Exception("Error calling permission API");
}
var res = await req.Content.ReadAsStringAsync();
return res;
}

View file

@ -186,6 +186,30 @@ namespace BMA.EHR.Application.Repositories
}
}
public async Task<GetProfileByKeycloakIdDto?> GetProfileByKeycloakIdNewAsync(Guid keycloakId, string? accessToken)
{
try
{
var apiPath = $"{_configuration["API"]}/org/dotnet/by-keycloak/{keycloakId}";
var apiKey = _configuration["API_KEY"];
var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey);
if (apiResult != null)
{
var raw = JsonConvert.DeserializeObject<GetProfileByKeycloakIdResultDto>(apiResult);
if (raw != null)
return raw.Result;
}
return null;
}
catch
{
throw;
}
}
public async Task<GetProfileLeaveByKeycloakDto?> GetProfileLeaveByKeycloakIdAsync(Guid keycloakId, string? accessToken)
{
try

View file

@ -144,12 +144,22 @@ namespace BMA.EHR.Domain.Middlewares
{
stopwatch.Stop();
// อ่านข้อมูล response ก่อนที่ stream จะถูก dispose
string? responseBodyForLogging = null;
if (memoryStream.Length > 0)
{
memoryStream.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(memoryStream, leaveOpen: true);
responseBodyForLogging = await reader.ReadToEndAsync();
memoryStream.Seek(0, SeekOrigin.Begin);
}
// ทำ logging แบบ fire-and-forget เพื่อไม่ block response
_ = Task.Run(async () =>
{
try
{
await LogRequestAsync(context, _elasticClient!, startTime, stopwatch, pf, keycloakId, requestBodyJson, memoryStream, caughtException);
await LogRequestAsync(context, _elasticClient!, startTime, stopwatch, pf, keycloakId, requestBodyJson, responseBodyForLogging, caughtException);
}
catch (Exception ex)
{
@ -393,7 +403,7 @@ namespace BMA.EHR.Domain.Middlewares
}
private async Task LogRequestAsync(HttpContext context, ElasticClient client, DateTime startTime, Stopwatch stopwatch,
GetProfileByKeycloakIdLocal? pf, string keycloakId, string? requestBodyJson, MemoryStream memoryStream, Exception? caughtException)
GetProfileByKeycloakIdLocal? pf, string keycloakId, string? requestBodyJson, string? responseBodyForLogging, Exception? caughtException)
{
try
{
@ -412,48 +422,42 @@ namespace BMA.EHR.Domain.Middlewares
string? message = null;
string? responseBodyJson = null;
// อ่านข้อมูลจาก Response (ลด serialization ที่ซ้ำ)
if (memoryStream.Length > 0)
// ใช้ response body ที่ส่งมาจากการอ่านก่อนหน้า
if (!string.IsNullOrEmpty(responseBodyForLogging))
{
memoryStream.Seek(0, SeekOrigin.Begin);
var responseBody = new StreamReader(memoryStream).ReadToEnd();
var contentType = context.Response.ContentType ?? "";
var isFileResponse = !contentType.StartsWith("application/json") && !contentType.StartsWith("text/html") && (
contentType.StartsWith("application/") ||
contentType.StartsWith("image/") ||
contentType.StartsWith("audio/") ||
context.Response.Headers.ContainsKey("Content-Disposition")
);
if (!string.IsNullOrEmpty(responseBody))
if (isFileResponse)
{
var contentType = context.Response.ContentType ?? "";
var isFileResponse = !contentType.StartsWith("application/json") && !contentType.StartsWith("text/html") && (
contentType.StartsWith("application/") ||
contentType.StartsWith("image/") ||
contentType.StartsWith("audio/") ||
context.Response.Headers.ContainsKey("Content-Disposition")
);
if (isFileResponse)
responseBodyJson = "";
message = "success";
}
else
{
// ใช้ response body ที่มีอยู่แล้วโดยไม่ serialize ซ้ำ
responseBodyJson = responseBodyForLogging;
try
{
responseBodyJson = "";
message = "success";
var json = JsonSerializer.Deserialize<JsonElement>(responseBodyForLogging);
if (json.ValueKind == JsonValueKind.Array)
{
message = "success";
}
else if (json.TryGetProperty("message", out var messageElement))
{
message = messageElement.GetString();
}
}
else
catch
{
// ใช้ response body ที่มีอยู่แล้วโดยไม่ serialize ซ้ำ
responseBodyJson = responseBody;
try
{
var json = JsonSerializer.Deserialize<JsonElement>(responseBody);
if (json.ValueKind == JsonValueKind.Array)
{
message = "success";
}
else if (json.TryGetProperty("message", out var messageElement))
{
message = messageElement.GetString();
}
}
catch
{
message = caughtException?.Message ?? "Unknown error";
}
message = caughtException?.Message ?? "Unknown error";
}
}
}
@ -467,7 +471,7 @@ namespace BMA.EHR.Domain.Middlewares
{
logType = logType,
ip = context.Connection.RemoteIpAddress?.ToString(),
rootId = pf?.RootId,
rootId = pf?.RootDnaId,
systemName = SystemName,
startTimeStamp = startTime.ToString("o"),
endTimeStamp = endTime.ToString("o"),
@ -660,7 +664,7 @@ namespace BMA.EHR.Domain.Middlewares
{
try
{
var apiPath = $"{_configuration["API"]}/org/dotnet/keycloak/{keycloakId}";
var apiPath = $"{_configuration["API"]}/org/dotnet/by-keycloak/{keycloakId}";
var apiKey = _configuration["API_KEY"];
var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey);