[ASP.NET Core] 更改 Api 回應的參數命名規則(PascalCase 及 CamelCase)

更改 Api 回應的參數命名規則(PascalCase 及 CamelCase)

在專案上有建立了一個 Middleware,把 exception 轉為自訂的 response 格式回應出去,結果發現從 action 出來的是 CamelCase,middleware 處理完的是 PascalCase,導致前端會依照情況不同拿到 Error 跟 error,為了讓兩邊統一,筆記一下做法


讓 System.Text.Json 的回應為 PascalCase

.NetCore 3.X的Json函式庫為System.Text.Json,而API回應格式預設為小寫開頭的駝峰式命名(camelCase),以WebApi的範例為例

[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
    var rng = new Random();
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    })
    .ToArray();
}
public class WeatherForecast
{
    public DateTime Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string Summary { get; set; }
}

從 PostMan 發出請求拿到的回應

若要讓回應格式改為 PascalCase,需要在 Startup 加上

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.PropertyNamingPolicy = null;
        });
}

接著Run起來再發一次請求,這次的回應就沒有被改成 CamelCase 了


Json.Net 的回應返回 PascalCase

雖然在 .NetCore 3.X 了,但是有些情況還是希望可以使用 Json.Net,所以接著把 Json.Net 裝上去

dotnet add package Newtonsoft.Json
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson

然後在 Startup 加入 Json.Net 的服務

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.PropertyNamingPolicy = null;
        });
}

再次呼叫 API,完美的又拿到了 CamelCase 的回應

因為已經改用 Json.Net 來做轉序列化的動作了,所以需要調整 AddNewtonsoftJson 的 options

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ContractResolver = new DefaultContractResolver();
        })
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.PropertyNamingPolicy = null;
        });
}

再次對API發出請求,預期的返回 PascalCase 的回應


Json.Net Serialize CamelCase

當發現上述的問題的時候,前端已經使用 CamelCase 串接了不少的頁面,評估成本還是有後端統一丟 CamelCase 比較省工一點,下面是處理 Exception 的 Middleware

public class ExceptionMiddleware
{
    private readonly ILoggerFactory _loggerFactory;
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _loggerFactory = loggerFactory;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next.Invoke(context);
        }
        catch (Exception ex)
        {
            var logger = _loggerFactory.CreateLogger("ExceptionHandler");
                logger.LogError(ex, ex.Message);

            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            context.Response.ContentType = "application/json";
            await context.Response.WriteAsync(JsonConvert.SerializeObject(new
            {
                Code = HttpStatusCode.InternalServerError,
                Error = "Server Error",
            }));
        }
    }
}

先把原本在 Startup 上面加上的設定先拿掉,讓API回應為 CamelCase

稍微修改讓他拋出一個 Exception

這邊就會看到了兩種回應兩種的命名 case,接著只需要調整 Middleware,改用 SerializeObject 的另一個多載

var response = new
{
    Code = HttpStatusCode.InternalServerError,
    Error = "Server Error",
};
var settings = new JsonSerializerSettings()
{
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};
await context.Response.WriteAsync(JsonConvert.SerializeObject(response, settings));

這樣在 Middleware 處理後的回應也是 CamelCase 了