ปรับ Middleware โดยรวม Exception + LogWriter ไว้ด้วยกัน

This commit is contained in:
Suphonchai Phoonsawat 2025-06-24 10:42:11 +07:00
parent f4b3eeac76
commit 2e77371316
5 changed files with 744 additions and 98 deletions

View file

@ -17,85 +17,166 @@ namespace BMA.EHR.Domain.Middlewares
public async Task Invoke(HttpContext context)
{
Console.WriteLine("=== ErrorHandlerMiddleware Start ===");
try
{
await _next(context);
Console.WriteLine($"Request completed with status: {context.Response.StatusCode}");
// จัดการ response format หลังจาก request ผ่าน pipeline แล้ว
await FormatResponse(context);
}
catch (ObjectDisposedException)
{
Console.WriteLine("ObjectDisposedException caught in main Invoke");
return;
}
catch (OperationCanceledException)
{
Console.WriteLine("OperationCanceledException caught in main Invoke");
return;
}
catch (Exception error)
{
Console.WriteLine($"Exception caught in main Invoke: {error.Message}");
// จัดการ exception และ format เป็น response
await FormatExceptionResponse(context, error);
}
Console.WriteLine("=== ErrorHandlerMiddleware End ===");
}
private static async Task FormatResponse(HttpContext context)
{
try
{
if (context?.Response == null)
return;
var response = context.Response;
var statusCode = response.StatusCode;
// ตรวจสอบว่า response ยังไม่ถูกส่งและเป็น status code ที่ต้องการจัดการ
if (!response.HasStarted &&
(statusCode == (int)HttpStatusCode.Unauthorized || statusCode == (int)HttpStatusCode.Forbidden))
{
var responseModel = new ResponseObject
{
Status = statusCode,
Message = statusCode == (int)HttpStatusCode.Unauthorized
? GlobalMessages.NotAuthorized
: GlobalMessages.ForbiddenAccess
};
// Debug log
Console.WriteLine($"FormatResponse: StatusCode={statusCode}, HasStarted={response.HasStarted}");
response.ContentType = "application/json";
// จัดการเฉพาะ status code ที่ต้องการ format และ response ยังไม่เริ่ม
if (!response.HasStarted && ShouldFormatResponse(statusCode))
{
Console.WriteLine($"Formatting response for status: {statusCode}");
var responseModel = CreateResponseModel(statusCode);
// Clear และตั้งค่าใหม่
response.Clear();
response.StatusCode = statusCode; // เซ็ตกลับไป
response.ContentType = "application/json; charset=utf-8";
// ใช้ JsonSerializer แทน WriteAsJsonAsync เพื่อความปลอดภัย
var jsonResponse = JsonSerializer.Serialize(responseModel);
await response.WriteAsync(jsonResponse);
Console.WriteLine($"Response formatted successfully: {jsonResponse}");
}
}
catch (Exception error)
catch (ObjectDisposedException)
{
await HandleExceptionAsync(context, error);
Console.WriteLine("ObjectDisposedException in FormatResponse");
}
catch (Exception ex)
{
Console.WriteLine($"Error in FormatResponse: {ex.Message}");
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception error)
private static async Task FormatExceptionResponse(HttpContext context, Exception error)
{
var response = context.Response;
// ตรวจสอบว่า response ยังไม่ถูกส่งไป
if (response.HasStarted)
{
// ถ้า response เริ่มแล้ว ไม่สามารถแก้ไขได้ แค่ log
Console.WriteLine("Cannot write error response, stream already started.");
Console.WriteLine($"Error: {error}");
return;
}
try
{
// Clear response เฉพาะเมื่อยังไม่ได้เริ่มส่ง
response.Clear();
response.ContentType = "application/json";
response.StatusCode = (int)HttpStatusCode.InternalServerError;
Console.WriteLine($"FormatExceptionResponse: Error={error.Message}");
if (context?.Response == null)
return;
// สร้าง error message
var msg = error.Message;
var inner = error.InnerException;
while (inner != null)
var response = context.Response;
Console.WriteLine($"Response HasStarted: {response.HasStarted}");
if (!response.HasStarted)
{
msg += $" {inner.Message}\r\n";
inner = inner.InnerException;
// Clear และตั้งค่า response
response.Clear();
response.StatusCode = (int)HttpStatusCode.InternalServerError;
response.ContentType = "application/json; charset=utf-8";
var responseModel = new ResponseObject
{
Status = response.StatusCode,
Message = GlobalMessages.ExceptionOccured,
Result = GetErrorMessage(error)
};
var jsonResponse = JsonSerializer.Serialize(responseModel);
await response.WriteAsync(jsonResponse);
Console.WriteLine($"Exception response formatted: {jsonResponse}");
}
var responseModel = new ResponseObject
else
{
Status = response.StatusCode,
Message = GlobalMessages.ExceptionOccured,
Result = msg
};
// ใช้ JsonSerializer และ WriteAsync เพื่อหลีกเลี่ยงปัญหา stream
var jsonResponse = JsonSerializer.Serialize(responseModel);
await response.WriteAsync(jsonResponse);
Console.WriteLine("Cannot format exception response - response already started");
}
}
catch (Exception writeError)
catch (ObjectDisposedException)
{
// ถ้าเขียน response ไม่ได้ ให้ log error
Console.WriteLine("Failed to write error response:");
Console.WriteLine($"Original Error: {error}");
Console.WriteLine($"Write Error: {writeError}");
Console.WriteLine("ObjectDisposedException in FormatExceptionResponse");
}
catch (Exception ex)
{
Console.WriteLine($"Error in FormatExceptionResponse: {ex.Message}");
}
}
private static bool ShouldFormatResponse(int statusCode)
{
// กำหนด status code ที่ต้องการ format
return statusCode == (int)HttpStatusCode.Unauthorized ||
statusCode == (int)HttpStatusCode.Forbidden ||
statusCode == (int)HttpStatusCode.BadRequest ||
statusCode == (int)HttpStatusCode.NotFound ||
statusCode == (int)HttpStatusCode.Conflict ||
statusCode == (int)HttpStatusCode.UnprocessableEntity ||
statusCode == (int)HttpStatusCode.InternalServerError; // 500
}
private static ResponseObject CreateResponseModel(int statusCode)
{
var message = statusCode switch
{
(int)HttpStatusCode.Unauthorized => GlobalMessages.NotAuthorized,
(int)HttpStatusCode.Forbidden => GlobalMessages.ForbiddenAccess,
(int)HttpStatusCode.BadRequest => "Bad Request",
(int)HttpStatusCode.NotFound => "Resource Not Found",
(int)HttpStatusCode.Conflict => "Conflict",
(int)HttpStatusCode.UnprocessableEntity => "Validation Error",
(int)HttpStatusCode.InternalServerError => GlobalMessages.ExceptionOccured,
_ => "Error"
};
return new ResponseObject
{
Status = statusCode,
Message = message
};
}
private static string GetErrorMessage(Exception error)
{
var msg = error.Message;
var inner = error.InnerException;
while (inner != null)
{
msg += $" {inner.Message}\r\n";
inner = inner.InnerException;
}
return msg;
}
}
}