日计不足涓滴成河-自定义响应结果格式化器

什么是响应结果

响应结果就是,在客户端向服务器发出请求后,服务器根据客户端的请求参数,给出的结果,这就是一个完整的响应结果过程。

响应的结果包含的内容非常多,主要的有 HTTP Status Code,Content-Type,Content 等等,在这里不再一一赘述。

一般情况下,在 .NET MVC 中,如果是 API 接口,默认使用 JsonOutputFormatter 对结果进行格式化。

但是也不排除某些情况下,我们需要对业务进行兼容化的设置,比如部分接口使用 xml,部分接口使用自定义的格式,需求的响应是第一要务。

常见响应结果格式化器

在 .NET(介于官方改名,咱也不叫 Core 了哈) MVC中,有几种内置的常见响应结果格式化器,他们分别是:

0、OutputFormatter(基类)
1、TextOutputFormatter(基类)
2、StringOutputFormatter
3、StreamOutputFormatter
4、JsonOutputFormatter
5、XmlSerializerOutputFormatter

由于这几种常见的格式化器的存在,我们可以放心的在 .NET MVC 中使用 请求-> 响应 过程,而不必关心他具体的实现。

来自天气预报的示例

默认的响应结果格式json

private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private IEnumerable<WeatherForecast> GetWeatherForecast()
{
var rng = new Random();
return Enumerable.Range(1, 3).Select(index => new WeatherForecast{Date = DateTime.Now.AddDays(index),TemperatureC = rng.Next(-20, 55),Summary = Summaries[rng.Next(Summaries.Length)]}).ToArray();
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return GetWeatherForecast();
}

当我们请求上面的 API 接口,将得到下面的默认输出结果。

[{
"date": "2020-10-24T17:19:05.4638588+08:00",
"temperatureC": 2,
"temperatureF": 35,
"summary": "Cool"},{
"date": "2020-10-25T17:19:05.464602+08:00",
"temperatureC": 18,
"temperatureF": 64,
"summary": "Sweltering"},{
"date": "2020-10-26T17:19:05.4646057+08:00",
"temperatureC": -14,
"temperatureF": 7,
"summary": "Mild"}
]

这很好,是我们想要的结果。

Xml响应结果格式器

在上面的天气预报示例中,API接口默认使用了 json 格式输出响应结果。

在不改动业务代码的情况下,我们可以增加一种 xml 输出结果,具体做法就是增加一个 API 接口,然后在 startup.cs 中添加 xml 格式化器。

[Produces("application/xml")]
[HttpGet("xml")]
public IEnumerable<WeatherForecast> Xml()
{
return GetWeatherForecast();
}

配置 Xml 格式器 XmlDataContractSerializerOutputFormatter

public void ConfigureServices(IServiceCollection services)
{services.AddControllers(configure =>{configure.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());});
}

这个时候再请求 API 地址:/weatherforecast/xml ,我们将会得到的结果如下

<ArrayOfWeatherForecast xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/CustomBinder">
<WeatherForecast>
<Date>2020-10-24T17:24:19.1047116+08:00</Date>
<Summary>Scorching</Summary>
<TemperatureC>49</TemperatureC>
</WeatherForecast>
<WeatherForecast>
<Date>2020-10-25T17:24:19.1047219+08:00</Date>
<Summary>Cool</Summary>
<TemperatureC>6</TemperatureC>
</WeatherForecast>
<WeatherForecast>
<Date>2020-10-26T17:24:19.1047221+08:00</Date>
<Summary>Freezing</Summary>
<TemperatureC>-20</TemperatureC>
</WeatherForecast>
</ArrayOfWeatherForecast>

ProducesAttribute 特性(内容协定)

API 接口 /xml 的特性标注多了一个 [Produces("application/xml")]正是得益于 ProducesAttribute 特性,我们可以在 MVC 框架内随意的定制响应结果。

ProducesAttribute 和其它的特性类没有太多的区别,其基本原理就是使用用户指定的 contentType 参数(本例中为 application/xml) 到 OutputFormatters 中查找对应类型的 Formatters。

如果找到了,就使用该 Formatters 格式化响应结果,如果没有找到,就抛出 No output formatter was found for content types 的警告,同时,客户端会收到一个  406(Not Acceptable) 的响应结果。

我想要更多-自定义格式化器

没错,上面的几种常见的格式化器虽然非常好用。但是,我现在要对接一个旧的第三方客户端,该客户端采用的是 url 参数请求协议包,很明显,由于这个客户端过于年长(假装找不到维护人员),只能在服务器端进行兼容了。

不过也不用过于担心,开发一个自定义的格式化器还是非常简单的。我们只需要定义一个继承自 TextOutputFormatter 的子类即可,其中有小部分需要编写的代码。

需求

我们接到的需求是兼容 url 方式的请求参数响应结果,经过调研,确认格式如下

key=value&key=value&key=value

需求调研清楚后,编码的速度就得跟上了

定义格式化器 WeatherOutputFormatter

public class WeatherOutputFormatter : TextOutputFormatter
{
private readonly static Type WeatherForecastType = typeof(WeatherForecast);
public WeatherOutputFormatter(){SupportedEncodings.Add(Encoding.UTF8);SupportedEncodings.Add(Encoding.Unicode);SupportedMediaTypes.Add("text/weather");}
public override bool CanWriteResult(OutputFormatterCanWriteContext context){
if (context == null){
throw new ArgumentNullException(nameof(context));}
if (context.ObjectType == WeatherForecastType || context.Object is WeatherForecast || context.ObjectType.GenericTypeArguments[0] == WeatherForecastType){
return base.CanWriteResult(context);}
return false;}
private string WriterText(IEnumerable<WeatherForecast> weathers){StringBuilder builder = new StringBuilder();
foreach (var wealther in weathers){builder.Append(WriterText(wealther));}
return builder.ToString();}
private string WriterText(WeatherForecast weather) => $"date={WebUtility.UrlEncode(weather.Date.ToString())}&temperatureC={weather.TemperatureC}&temperatureF={weather.TemperatureF}&summary={WebUtility.UrlEncode(weather.Summary)}";
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding){
if (context == null){
throw new ArgumentNullException(nameof(context));}
if (selectedEncoding == null){
throw new ArgumentNullException(nameof(selectedEncoding));}
string text = string.Empty;
if (context.ObjectType == WeatherForecastType)text = WriterText(context.Object as WeatherForecast);
else if (context.ObjectType.GenericTypeArguments[0] == WeatherForecastType)text = WriterText(context.Object as IEnumerable<WeatherForecast>);
if (string.IsNullOrEmpty(text)){
await Task.CompletedTask;}
var response = context.HttpContext.Response;
await response.WriteAsync(text, selectedEncoding);}
}

正所谓一图胜千言,所以我给大家画了一张图,方便理解

从图中可以看出,我们只需要重写两个方法,同时编写一个自定义格式化逻辑即可完成,看起来还是非常简单的。

细心的同学可能发现了,在 WriterText 方法中,考虑到兼容性的问题,我们还将 url 中的 value 进行转义,可以说还是非常贴心的哈。

编写测试方法

[Produces("text/weather")]
[HttpGet("weather")]
public IEnumerable<WeatherForecast> Weather()
{
return GetWeatherForecast();
}

测试方法中定义 Produces("text/weather"),指定需要的 ContentType,同时,还需要将 WeatherOutputFormatter 添加到 OutputFormatters 中使用。

public void ConfigureServices(IServiceCollection services)
{services.AddControllers(configure =>{configure.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());configure.OutputFormatters.Add(new WeatherOutputFormatter());});
}

调用接口进行测试

请求 API 地址 /weather,得到结果如下

date=2020%2F10%2F27+10%3A35%3A36&temperatureC=42&temperatureF=107&summary=Scorchingdate=2020%2F10%2F28+10%3A35%3A36&temperatureC=28&temperatureF=82&summary=Freezingdate=2020%2F10%2F29+10%3A35%3A36&temperatureC=17&temperatureF=62&summary=Sweltering

结束语

至此,自定义格式化器已经完成,本文通过一个简单的示例实现,帮助大家理解如何在 MVC 中使用自定义格式化器,文章篇幅不长,做图花了点心思,欢迎您的关注。

示例代码托管在:

https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/CustomBinder

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker 容器启动顺序_Docker容器启动时初始化Mysql数据库

1. 前言 Docker在开发中使用的越来越多了&#xff0c;最近搞了一个Spring Boot应用&#xff0c;为了方便部署将Mysql也放在Docker中运行。那么怎么初始化 SQL脚本以及数据呢&#xff1f; 我这里有两个传统方案。 第一种方案是在容器启动后手动导入&#xff0c;太low了不行。第二…

后端学习 - JVM(上)内存与垃圾回收

JVM 架构图 文章目录一 JVM 简介二 类加载子系统&#xff1a;1 作用2 类的三个加载过程3 类加载器的分类4 双亲委派机制 & Tomcat为何不遵循5 两个 class 对象为同一个类的必要条件三 运行时数据区&#xff1a;PC寄存器&#xff08;Program Counter Register&#xff09;四…

SM2 国密算法被 Linux 内核社区接受

喜欢就关注我们吧&#xff01;10 月 25 日&#xff0c;有开发者发文称&#xff0c;SM2 国密算法终于被 Linux 内核社区接受了。该作者表示&#xff0c;SM2 的补丁已经更新到了 v7 版本&#xff0c;这个版本的补丁最终被社区接受&#xff0c;目前已经合并到了 Linux 主线的 5.10…

后端学习 - MyBatis

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的 持久层框架 文章目录一 基于配置文件的 MyBatis 搭建1 搭建过程&#xff08;增删改&#xff09;2 查询操作3 特殊操作二 MyBatis 获取参数值的方式1 单个字面量类型的参数2 多个字面量类型的参数3 Map 类型的参数4 实体…

向下兼容性格什么意思_担心对方只是向下兼容,并不是从心底里接纳我怎么办?...

无需刻意累计帮助了44人题主你好&#xff0c;不知道什么时候“向下兼容”这个词被用在了人际关系上&#xff0c;只就我个人所了解的话&#xff0c;这是一个很不严谨的用法。因为在自我接纳中用了“向下”本身就意味着不平等和不接纳。形容一个人“向下兼容”本身就自带了否认倾…

国产操作系统发展离不开人才和市场

日前&#xff0c;中国 1024 程序员节盛大举行&#xff0c;一大批开源大咖齐聚千年岳麓&#xff0c;围绕开源标准、生态、人才发展等主题分享&#xff0c;共议开源软件与操作系统未来。其中&#xff0c;统信软件总经理刘闻欢表示&#xff0c;“有了市场才会被真正的用起来”&…

zynq网络时钟控制寄存器_ZYNQ笔记(6):普通自定义IP封装实现PL精准定时中断...

软件的定时中断很难控制精准触发沿的位置&#xff0c;可以通过 PL-PS 的中断完成精准的定时中断。PL 的中断通过 Verilog 代码产生&#xff0c;这样紧密结合 PS-PL 的处理&#xff0c;发挥各自的优势。一、PL 侧定时中断1.实际要求① 上升沿中断&#xff1b;② 高电平宽度不小于…

后端学习 - Redis

文章目录一 Redis 概述Redis 为什么是单线程&#xff0c;单线程为什么这么快&#xff1f;数据存储结构二 常用数据类型1 String2 HashHash 的扩容机制&#xff1a;渐进式 rehash*3 List4 Set5 Zset三 Redis 事务1 乐观锁与 watch 命令2 事务的三个特性四 Redis 持久化1 RDB(Red…

再被补刀!Flash又遭抛弃,你会怀念它吗?

喜欢就关注我们吧&#xff01;微软近日发布通知&#xff0c;称更新了关于 Adobe Flash Player 的删除。微软更新目录站点可下载更新 KB4577586&#xff0c;用于删除 Flash Player。此更新适用于所有受支持的操作系统版本。重要版本 Windows 10 和 Windows 8.1 的可选更新也将在…

4位加法器的设计代码verilog_HDLBits:在线学习Verilog(六 · Problem 25-29)

本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题&#xff0c;并附上解答和一些作者个人的理解&#xff0c;相信无论是想 7 分钟精通 Verilog&#xff0c;还是对 Verilog 和数电知识查漏补缺的同学&#xff0c;都能从中有所收获。附上传送门&#xff1a;M…

译 | 将数据从Cosmos DB迁移到本地JSON文件

点击上方蓝字关注“汪宇杰博客”原文&#xff1a;Azure Tips and Tricks翻译&#xff1a;汪宇杰在Cosmos DB中使用数据迁移工具有一项重复的任务是将数据从一种数据库格式迁移到另一种数据库格式。我最近使用Cosmos DB作为数据库来存储Ignite大会发出的所有推文。然而一旦获得了…

在线教育后端开发项目总结

文章目录一 数据库访问接口1 MyBatis2 Spring Data JPA3 Spring Data MongoDB二 数据库1 MySQL2 MongoDB3 Redis三 开发规范化、响应格式与异常处理1 开发规范2 响应格式3 异常处理四 RabbitMQ五 Spring Cloud 相关工具1 Eureka2 Ribbon3 Feign4 Zuul 网关六 搜索服务1 Elastic…

通讯故障_掌握PLC必备知识,人机界面和 PLC 出现通讯故障如何分析解决

此次主要在阐述人机界面和 PLC 通讯时的模式状态&#xff0c;并列举了通讯故障实例。帮助大伙加深对这俩者的了解&#xff0c;掌握起来也不再是难题&#xff0c;解决掉拦路虎。一 台数 显 四 辊 卷 板 机PLC 控 制 系 统 核 心 与 人机界面在使用过程中&#xff0c;出现人机界面…

.NET架构小技巧(4)——反射,架构人员法宝II

上一篇博文中&#xff0c;利用属性反射的特点&#xff0c;用两个方法完成了字符转实体&#xff0c;实体转字符的工作&#xff0c;但有些复杂的场景&#xff0c;上面方法就没那么好用了&#xff0c;就需要更复杂的方式来组装处理。先来看一个接口文档&#xff0c;下面是接口的调…

后端学习 - 设计模式与设计原则

文章目录设计原则1 单一职责原则2 开闭原则3 Liskov 替换原则4 依赖倒置原则5 接口隔离原则6 迪米特法则设计模式&#xff1a;创建型模式1 工厂模式2 抽象工厂模式3 单例模式设计模式&#xff1a;行为型模式1 观察者模式2 模板模式3 备忘录模式设计模式&#xff1a;结构型模式1…

ai的预览模式切换_AI字体制作,用AI制作创意阶梯式文字

本篇教程通过AI制作一款创意阶梯式文字&#xff0c;教程中有很多知识点需要掌握&#xff0c;比如路径分割为网络&#xff0c;3D效果应用等&#xff0c;我们要利用他们创造出我们需要的文字出来&#xff0c;具体是如何制作的&#xff0c;我们通过教程一起来学习一下吧。效果图&a…

.NET架构小技巧(5)——反射,架构人员法宝III

通过两篇博文&#xff0c;我们了解到&#xff0c;反射是通过非实例化(new)的手段来对对象和对象内的成员访问的&#xff0c;不仅仅如此&#xff0c;反射还可以突破访问修饰符的限制&#xff0c;以上帝视角来窥探对象内部全部成员(字段&#xff0c;属性&#xff0c;方法)&#x…

分类计数原理与分步计数原理_《分类计数原理与分步计数原理》优秀说课稿

《分类计数原理与分步计数原理》优秀说课稿一、本节内容的地位与重要性“分类计数原理与分步计数原理”是《高中数学》一节独特内容。这一节课与排列、组合的基本概念有着紧密的联系&#xff0c;通过对这一节课的学习&#xff0c;既可以让学生接受、理解分类计数原理与分步计数…

新版本 Swashbuckle swagger 组件中的 坑

新版本 Swashbuckle swagger 组件中的 Servers 坑Intro上周做了公司的项目升级&#xff0c;从 2.2 更新到 3.1&#xff0c; swagger 直接更新到了最新&#xff0c;swagger 用的组件是 Swashbuckle.AspNetCore&#xff0c;然后遇到一个 swagger 的问题&#xff0c; 在本地测试是…

后端学习 - MySQL存储引擎、索引与事务

文章目录一 存储引擎1 MyISAM 与 InnoDB 的差异二 索引1 主键索引与二级索引、索引覆盖、延迟关联2 聚簇索引与非聚簇索引3 数据结构3.1 哈希表3.2 B树3.3 B树3.4 跳表3.5 为什么不使用红黑树3.6 为什么不使用B树**4 索引下推 ICP **5 索引失效&#xff08;索引不命中&#xff…