客户要求ASP.NET Core API返回特定格式,怎么办?

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了客户要求ASP.NET Core API返回特定格式,怎么办?相关的知识,希望对你有一定的参考价值。

当ASP.NET Core API提供给到外部系统使用时,在某些情况下,可能需要根据这些外部系统的要求来格式化数据。

比如,客户就要求API的返回值属性名必须是PascalCase(如UserName),但是这些API需要同时提供给内部系统使用,默认都是CamelCase(如userName)。

怎么办?

虽然可以为外部系统重新做一套API,但是代价太大!能不能从自定义API的返回值上想办法?

在微软官方文档上找到一篇设置 ASP.NET Core Web API 中响应数据的格式[1],介绍了响应格式 URL 映射。

使用FormatFilter可以根据请求路径的路由映射将相应映射到相应的格式上。

希望达到的效果:

[ApiController]
[Route("[controller]")]
[FormatFilter]
public class WeatherForecastController : ControllerBase
{
    [HttpGet("{format?}")]
    public IEnumerable<WeatherForecast> Get()

路由响应格式
WeatherForecast默认格式CamelCase
WeatherForecast?format=json2PascalCase

代码实现

首先,需要让API支持自定义格式,返回MediaType还是application/json

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.FormatterMappings.SetMediaTypeMappingForFormat
            ("json2", MediaTypeHeaderValue.Parse("application/json"));
    });
}

接着,我们需要替换掉默认的Json OutputFomatter:

for (int i = 0; i < options.OutputFormatters.Count; i++)
{
    if (options.OutputFormatters[i] is Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter jsonOutputFormatter)
    {
        options.OutputFormatters[i] = new CustomJsonOutputFormatter(jsonOutputFormatter.SerializerOptions);
        break;
    }
} 

CustomJsonOutputFormatter的代码如下:

public class CustomJsonOutputFormatter : SystemTextJsonOutputFormatter
{
    private readonly SystemTextJsonOutputFormatter pascalCaseFormater;
    public CustomJsonOutputFormatter(JsonSerializerOptions jsonSerializerOptions) : base(jsonSerializerOptions)
    {
        var newOptions = new JsonSerializerOptions(jsonSerializerOptions);
        newOptions.PropertyNamingPolicy = null;
        pascalCaseFormater = new SystemTextJsonOutputFormatter(newOptions);
    }

    public override Task WriteAsync(OutputFormatterWriteContext context)
    {
        if (GetFormat(context) == "json2")
        {
            return pascalCaseFormater.WriteAsync(context);
        }
        return base.WriteAsync(context);
    }

    private string? GetFormat(OutputFormatterWriteContext context)
    {
        if (context.HttpContext.Request.RouteValues.TryGetValue("format", out var obj))
        {
            var routeValue = Convert.ToString(obj, CultureInfo.InvariantCulture);
            return string.IsNullOrEmpty(routeValue) ? null : routeValue;
        }

        var query = context.HttpContext.Request.Query["format"];
        if (query.Count > 0)
        {
            return query.ToString();
        }

        return "json";
    }
}

如果format是json2,就用pascalCaseFormater处理,否则使用默认处理。

小插曲: 需要设置pascalCaseFormater的JsonSerializerOptions.PropertyNamingPolicy属性,指定用于将对象的属性名称转换为其他格式(例如PascalCase)的策略,本来还准备实现一个PascalCasePolicy但是转念一想,C#本身的Property名不就是PascalCase的吗?!直接将PropertyNamingPolicy设为null不处理就行了。

结论

最后,运行结果如下: 

完全满足了要求,只需要客户在每个API请求URL上加上?format=json2即可。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!

参考资料

[1]

设置 ASP.NET Core Web API 中响应数据的格式: https://docs.microsoft.com/zh-cn/aspnet/core/web-api/advanced/formatting?view=aspnetcore-5.0

以上是关于客户要求ASP.NET Core API返回特定格式,怎么办?的主要内容,如果未能解决你的问题,请参考以下文章

客户要求ASP.NET Core API返回特定格式,怎么办?(续)

ASP.NET Core API 在从 React 客户端调用时返回 401

使用ETag协议实现ASP.NET Core API缓存

Blazor ASP.Net Core 3.1 Web API 在发布时返回 404 错误

ASP.NET Core Refit Client for RESTful API:如何划分客户端

ASP.NET Core MVC 使用 api +javascript 客户端与 ajax