fix enum convertor for api and razor

This commit is contained in:
MahanCh
2025-06-25 11:00:35 +03:30
parent d27b8484a2
commit 92f68d8555
5 changed files with 181 additions and 7 deletions

View File

@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization;
using System.Text.Json;
namespace ServiceHost.MiddleWare;
public class ApiJsonEnumFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// قبل از اکشن نیازی نیست کاری کنیم
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result is ObjectResult objectResult)
{
var enumConverter = new JsonStringEnumConverter();
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
options.Converters.Add(enumConverter);
var json = JsonSerializer.Serialize(objectResult.Value, options);
context.Result = new ContentResult
{
Content = json,
ContentType = "application/json",
StatusCode = objectResult.StatusCode
};
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.AspNetCore.Mvc.Formatters;
using System.Text.Json;
using System.Text;
namespace ServiceHost.MiddleWare;
public class ConditionalJsonOutputFormatter : TextOutputFormatter
{
private readonly JsonSerializerOptions _options;
public ConditionalJsonOutputFormatter(JsonSerializerOptions options)
{
_options = options;
SupportedMediaTypes.Add("application/json");
SupportedEncodings.Add(System.Text.Encoding.UTF8);
}
public override bool CanWriteResult(OutputFormatterCanWriteContext context)
{
var path = context.HttpContext.Request.Path;
return path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase);
}
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
await JsonSerializer.SerializeAsync(response.Body, context.Object, context.ObjectType ?? context.Object?.GetType() ?? typeof(object), _options);
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text;
public class CustomJsonResultExecutor : IActionResultExecutor<JsonResult>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<CustomJsonResultExecutor> _logger;
public CustomJsonResultExecutor(IHttpContextAccessor httpContextAccessor, ILogger<CustomJsonResultExecutor> logger)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public async Task ExecuteAsync(ActionContext context, JsonResult result)
{
var response = context.HttpContext.Response;
response.ContentType = "application/json; charset=utf-8";
var requestPath = context.HttpContext.Request.Path;
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false
};
if (requestPath.HasValue && requestPath.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase))
{
// API → enum به صورت string
options.Converters.Add(new JsonStringEnumConverter());
}
// Else: Razor → enum بدون converter (یعنی عدد)
var json = JsonSerializer.Serialize(result.Value, options);
await response.WriteAsync(json, Encoding.UTF8);
}
}

View File

@@ -0,0 +1,61 @@
using System.Text.Json;
using System.Text;
namespace ServiceHost.MiddleWare;
public class RazorJsonEnumOverrideMiddleware
{
private readonly RequestDelegate _next;
public RazorJsonEnumOverrideMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// نگه‌دار خروجی
var originalBody = context.Response.Body;
using var newBody = new MemoryStream();
context.Response.Body = newBody;
await _next(context); // اجرای مرحله بعدی
// فقط برای مسیرهای غیر /api و وقتی Content-Type = application/json
if (!context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase) &&
context.Response.ContentType?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true)
{
newBody.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(newBody);
var originalJson = await reader.ReadToEndAsync();
// JSON رو deserialize و دوباره serialize می‌کنیم بدون EnumConverter
try
{
var obj = JsonSerializer.Deserialize<object>(originalJson);
var newJson = JsonSerializer.Serialize(obj, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
context.Response.Body = originalBody;
context.Response.ContentLength = Encoding.UTF8.GetByteCount(newJson);
await context.Response.WriteAsync(newJson);
return;
}
catch
{
// fallback if deserialization fails
context.Response.Body = originalBody;
newBody.Seek(0, SeekOrigin.Begin);
await newBody.CopyToAsync(originalBody);
return;
}
}
// اگر شرط نداشت، همون خروجی قبلی رو منتقل کن
context.Response.Body = originalBody;
newBody.Seek(0, SeekOrigin.Begin);
await newBody.CopyToAsync(originalBody);
}
}

View File

@@ -21,6 +21,10 @@ using _0_Framework.Application.UID;
using _0_Framework.Exceptions.Handler;
using Microsoft.OpenApi.Models;
using ServiceHost.Test;
using System.Text.Json.Serialization;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
@@ -51,6 +55,7 @@ var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb")
//builder.Services.AddSingleton<IMongoDatabase>(mongoDatabase);
#endregion
builder.Services.AddSingleton<IActionResultExecutor<JsonResult>, CustomJsonResultExecutor>();
PersonalBootstrapper.Configure(builder.Services, connectionString);
TestDbBootStrapper.Configure(builder.Services, connectionStringTestDb);
AccountManagementBootstrapper.Configure(builder.Services, connectionString);
@@ -142,11 +147,15 @@ builder.Services.AddAuthorization(options =>
// });
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
});
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//builder.Services.AddControllers(
//options=> {
// options.Filters.Add(new ApiJsonEnumFilter());
//});
builder.Services.AddRazorPages(options =>
@@ -181,8 +190,9 @@ builder.Services.AddSignalR();
#region Swagger
builder.Services.AddSwaggerGen(options =>
{
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.UseInlineDefinitionsForEnums();
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
@@ -321,6 +331,7 @@ app.UseAuthorization();
//app.UseLoginHandlerMiddleware();
//app.UseCheckTaskMiddleware();
app.UseMiddleware<RazorJsonEnumOverrideMiddleware>();
#endregion