当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=json2 | PascalCase |
代码实现
首先,需要让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