using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Nest; using System.Diagnostics; using System.Security.Claims; using System.Text.Encodings.Web; using System.Text.Json; using JsonSerializer = System.Text.Json.JsonSerializer; namespace BMA.EHR.Recurit.Exam.Service.Core { public class RequestLoggingMiddleware { private readonly RequestDelegate _next; private readonly IConfiguration _configuration; private string Uri = ""; private string IndexFormat = ""; private string SystemName = ""; public RequestLoggingMiddleware(RequestDelegate next, IConfiguration configuration) { _next = next; _configuration = configuration; Uri = _configuration["ElasticConfiguration:Uri"] ?? "http://192.168.1.40:9200"; IndexFormat = _configuration["ElasticConfiguration:IndexFormat"] ?? "bma-ehr-log-index"; //SystemName = _configuration["ElasticConfiguration:SystemName"] ?? "Unknown"; SystemName = "recruiting"; } public async Task Invoke(HttpContext context) { var settings = new ConnectionSettings(new Uri(Uri)) .DefaultIndex(IndexFormat); var client = new ElasticClient(settings); var startTime = DateTime.UtcNow; var stopwatch = Stopwatch.StartNew(); string? responseBodyJson = null; string? requestBodyJson = null; string requestBody = await ReadRequestBodyAsync(context); if (requestBody != "") { if (context.Request.HasFormContentType) { var form = await context.Request.ReadFormAsync(); // อ่าน form-data var formData = new Dictionary(); foreach (var field in form) { formData[field.Key] = field.Value.ToString(); } // อ่านไฟล์ที่ถูกส่งมา (ถ้ามี) if (form.Files.Count > 0) { var fileDataList = new List(); foreach (var file in form.Files) { fileDataList.Add(new { FileName = file.FileName, ContentType = file.ContentType, Size = file.Length }); } formData["Files"] = fileDataList; } requestBodyJson = JsonSerializer.Serialize(formData, new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true, Converters = { new DateTimeFixConverter() } }); } else { requestBodyJson = JsonSerializer.Serialize(JsonSerializer.Deserialize(requestBody), new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true, Converters = { new DateTimeFixConverter() } }); } } var originalBodyStream = context.Response.Body; using (var memoryStream = new MemoryStream()) { // เปลี่ยน stream ของ Response เพื่อให้สามารถอ่านได้ context.Response.Body = memoryStream; // Extract all required data from JWT token claims var keycloakId = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? Guid.Empty.ToString("D"); var prefix = context.User?.FindFirst("prefix")?.Value; var firstName = context.User?.FindFirst("given_name")?.Value; var lastName = context.User?.FindFirst("family_name")?.Value; var preferredUsername = context.User?.FindFirst("preferred_username")?.Value; var orgRootDnaId = context.User?.FindFirst("orgRootDnaId")?.Value; var orgChild1DnaId = context.User?.FindFirst("orgChild1DnaId")?.Value; var orgChild2DnaId = context.User?.FindFirst("orgChild2DnaId")?.Value; var orgChild3DnaId = context.User?.FindFirst("orgChild3DnaId")?.Value; var orgChild4DnaId = context.User?.FindFirst("orgChild4DnaId")?.Value; // Parse Guid values safely Guid? rootDnaId = Guid.TryParse(orgRootDnaId, out var rid) ? rid : null; Guid? child1DnaId = Guid.TryParse(orgChild1DnaId, out var c1) ? c1 : null; Guid? child2DnaId = Guid.TryParse(orgChild2DnaId, out var c2) ? c2 : null; Guid? child3DnaId = Guid.TryParse(orgChild3DnaId, out var c3) ? c3 : null; Guid? child4DnaId = Guid.TryParse(orgChild4DnaId, out var c4) ? c4 : null; await _next(context); // ดำเนินการต่อไปยัง Middleware อื่น ๆ stopwatch.Stop(); var processTime = stopwatch.ElapsedMilliseconds; var endTime = DateTime.UtcNow; var logType = context.Response.StatusCode switch { >= 500 => "error", >= 400 => "warning", _ => "info" }; string? message = null; // อ่านข้อมูลจาก Response หลังจากที่ได้ถูกส่งออกไป memoryStream.Seek(0, SeekOrigin.Begin); var responseBody = new StreamReader(memoryStream).ReadToEnd(); //if (responseBody != "") // responseBodyJson = JsonSerializer.Serialize(JsonSerializer.Deserialize(responseBody), new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true, Converters = { new DateTimeFixConverter() } }); //var json = JsonSerializer.Deserialize(responseBody); //if (json.ValueKind == JsonValueKind.Array) //{ // message = "success"; //} //else //{ // if (json.TryGetProperty("message", out var messageElement)) // { // message = messageElement.GetString(); // } //} if (!string.IsNullOrEmpty(responseBody)) { var contentType = context.Response.ContentType ?? ""; if (contentType.Equals( "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", StringComparison.OrdinalIgnoreCase)) { // Excel responseBodyJson = $"Excel file (Length={memoryStream.Length} bytes)"; message = "success"; } else if (contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { // JSON try { responseBodyJson = JsonSerializer.Serialize( JsonSerializer.Deserialize(responseBody), new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = true, Converters = { new DateTimeFixConverter() } }); var json = JsonSerializer.Deserialize(responseBody); if (json.ValueKind == JsonValueKind.Array) message = "success"; else if (json.TryGetProperty("message", out var messageElement)) message = messageElement.GetString(); } catch { // fallback ถ้า deserialize ไม่ได้ responseBodyJson = responseBody; message = "success"; } } else { // plain text / HTML / binary อื่น responseBodyJson = responseBody; message = "success"; } } var logData = new { logType = logType, ip = context.Connection.RemoteIpAddress?.ToString(), rootId = rootDnaId, systemName = SystemName, startTimeStamp = startTime.ToString("o"), endTimeStamp = endTime.ToString("o"), processTime = processTime, host = context.Request.Host.Value, method = context.Request.Method, endpoint = context.Request.Path + context.Request.QueryString, responseCode = context.Response.StatusCode == 304 ? "200" : context.Response.StatusCode.ToString(), responseDescription = message, input = requestBodyJson, output = responseBodyJson, userId = keycloakId, userName = $"{prefix ?? ""}{firstName ?? ""} {lastName ?? ""}".Trim(), user = preferredUsername ?? "" }; // เขียนข้อมูลกลับไปยัง original Response body memoryStream.Seek(0, SeekOrigin.Begin); await memoryStream.CopyToAsync(originalBodyStream); client.IndexDocument(logData); } //Log.Information("API Request Log: {@LogData}", logData); } private async Task ReadRequestBodyAsync(HttpContext context) { context.Request.EnableBuffering(); using var reader = new StreamReader(context.Request.Body, leaveOpen: true); var body = await reader.ReadToEndAsync(); context.Request.Body.Position = 0; return body; } } }