ASP.NET Core AutoWrapper 自定义响应输出
前言
AutoWrapper是一个简单可自定义全局异常处理程序和ASP.NET Core API响应的包装。他使用ASP.NET Core middleware拦截传入的HTTP请求,并将最后的结果使用统一的格式来自动包装起来.目的主要是让我们更多的关注业务特定的代码要求,并让包装器自动处理HTTP响应。这可以在构建API时加快开发时间,同时为HTTP响应试试我们统一的标准。
安装
AutoWrapper.Core从NuGet或通过CLI下载并安装
PM> Install-Package AutoWrapper.Core
在Startup.cs Configure方法中注册以下内容,但是切记要放在UseRouting前
app.UseApiResponseAndExceptionWrapper();
启动属性映射
默认情况下AutoWrapper将在成功请求成功时输出以下格式:
{
"message": "Request successful.",
"isError": false,
"result": [
{
"id": 7002,
"firstName": "Vianne",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
}
]
}
如果说不喜欢默认属性命名方式,那么我们可以通过AutoWrapperPropertyMap属性进行映射为我们需要指定的任何名称。例如我么可以将result属性的名称更改为data。如下所示
public class MapResponseObject
{
[AutoWrapperPropertyMap(Prop.Result)]
public object Data { get; set; }
}
然后将MapResponseObject类传递给AutpWrapper middleware
app.UseApiResponseAndExceptionWrapper<MapResponseObject>();
通过映射重新请求后,现在影响格式如下所示
{
"message": "Request successful.",
"isError": false,
"data": {
"id": 7002,
"firstName": "Vianne",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
}
}
可以从中看出result属性已经更换为data属性了
默认情况下AutoWrapper发生异常时将吐出以下响应格式
{
"isError": true,
"responseException": {
"exceptionMessage": "Unhandled Exception occurred. Unable to process the request."
}
}
而且如果在AutoWrapperOptions中设置了IsDebug,则将产生带有堆栈跟踪信息的类似信息
{
"isError": true,
"responseException": {
"exceptionMessage": " Input string was not in a correct format.",
"details": " at System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type)\r\n at System.Number.ParseInt32(ReadOnlySpan`1 value, NumberStyles styles, NumberFormatInfo info)\r\n …"
}
}
如果想将某些APIError属性名称更改为其他名称,只需要在以下代码中添加以下映射MapResponseObject
public class MapResponseObject
{
[AutoWrapperPropertyMap(Prop.ResponseException)]
public object Error { get; set; }
[AutoWrapperPropertyMap(Prop.ResponseException_ExceptionMessage)]
public string Message { get; set; }
[AutoWrapperPropertyMap(Prop.ResponseException_Details)]
public string StackTrace { get; set; }
}
通过如下代码来模拟错误
int num = Convert.ToInt32("10s");
现在映射后的输出如下所示
{
"isError": true,
"error": {
"message": " Input string was not in a correct format.",
"stackTrace": " at System.Number.ThrowOverflowOrFormatException(ParsingStatus status, TypeCode type)\r\n at System.Number.ParseInt32(ReadOnlySpan`1 value, NumberStyles styles, NumberFormatInfo info)\r\n …"
}
}
请注意APIError现在根据MapResponseObject类中定义的属性更改了模型的默认属性。
我们可以自由的选择映射任何属性,下面是映射属性相对应的列表
[AutoWrapperPropertyMap(Prop.Version)]
[AutoWrapperPropertyMap(Prop.StatusCode)]
[AutoWrapperPropertyMap(Prop.Message)]
[AutoWrapperPropertyMap(Prop.IsError)]
[AutoWrapperPropertyMap(Prop.Result)]
[AutoWrapperPropertyMap(Prop.ResponseException)]
[AutoWrapperPropertyMap(Prop.ResponseException_ExceptionMessage)]
[AutoWrapperPropertyMap(Prop.ResponseException_Details)]
[AutoWrapperPropertyMap(Prop.ResponseException_ReferenceErrorCode)]
[AutoWrapperPropertyMap(Prop.ResponseException_ReferenceDocumentLink)]
[AutoWrapperPropertyMap(Prop.ResponseException_ValidationErrors)]
[AutoWrapperPropertyMap(Prop.ResponseException_ValidationErrors_Field)]
[AutoWrapperPropertyMap(Prop.ResponseException_ValidationErrors_Message)]
自定义错误架构
AutoWrapper还提供了一个APIException可用于定义自己的异常的对象,如果想抛出自己的异常消息,则可以简单地执行以下操作
throw new ApiException("Error blah", 400, "511", "http://blah.com/error/511");
默认输出格式如下所示
{
"isError": true,
"responseException": {
"exceptionMessage": "Error blah",
"referenceErrorCode": "511",
"referenceDocumentLink": "http://blah.com/error/511"
}
}
当然我们可以自定义错误格式
public class MapResponseObject
{
[AutoWrapperPropertyMap(Prop.ResponseException)]
public object Error { get; set; }
}
public class Error
{
public string Message { get; set; }
public string Code { get; set; }
public InnerError InnerError { get; set; }
public Error(string message, string code, InnerError inner)
{
this.Message = message;
this.Code = code;
this.InnerError = inner;
}
}
public class InnerError
{
public string RequestId { get; set; }
public string Date { get; set; }
public InnerError(string reqId, string reqDate)
{
this.RequestId = reqId;
this.Date = reqDate;
}
}
然后我们可以通过如下代码进行引发我们错误
throw new ApiException(
new Error("An error blah.", "InvalidRange",
new InnerError("12345678", DateTime.Now.ToShortDateString())
));
输出格式如下所示
{
"isError": true,
"error": {
"message": "An error blah.",
"code": "InvalidRange",
"innerError": {
"requestId": "12345678",
"date": "10/16/2019"
}
}
}
使用自定义API响应格式
如果映射满足不了我们的需求。并且我们需要向API响应模型中添加其他属性,那么我们现在可以自定义自己的格式类,通过设置UseCustomSchema为true来实现,代码如下所示
app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { UseCustomSchema = true });
现在假设我们想在主API中响应中包含一个属性SentDate和Pagination对象,我们可能希望将API响应模型定义为以下格式
public class MyCustomApiResponse
{
public int Code { get; set; }
public string Message { get; set; }
public object Payload { get; set; }
public DateTime SentDate { get; set; }
public Pagination Pagination { get; set; }
public MyCustomApiResponse(DateTime sentDate, object payload = null, string message = "", int statusCode = 200, Pagination pagination = null)
{
this.Code = statusCode;
this.Message = message == string.Empty ? "Success" : message;
this.Payload = payload;
this.SentDate = sentDate;
this.Pagination = pagination;
}
public MyCustomApiResponse(DateTime sentDate, object payload = null, Pagination pagination = null)
{
this.Code = 200;
this.Message = "Success";
this.Payload = payload;
this.SentDate = sentDate;
this.Pagination = pagination;
}
public MyCustomApiResponse(object payload)
{
this.Code = 200;
this.Payload = payload;
}
}
public class Pagination
{
public int TotalItemsCount { get; set; }
public int PageSize { get; set; }
public int CurrentPage { get; set; }
public int TotalPages { get; set; }
}
通过如下代码片段进行测试结果
public async Task<MyCustomApiResponse> Get()
{
var data = await _personManager.GetAllAsync();
return new MyCustomApiResponse(DateTime.UtcNow, data,
new Pagination
{
CurrentPage = 1,
PageSize = 10,
TotalItemsCount = 200,
TotalPages = 20
});
}
运行后会得到如下影响格式
{
"code": 200,
"message": "Success",
"payload": [
{
"id": 1,
"firstName": "Vianne",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
},
{
"id": 2,
"firstName": "Vynn",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
},
{
"id": 3,
"firstName": "Mitch",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
}
],
"sentDate": "2019-10-17T02:26:32.5242353Z",
"pagination": {
"totalItemsCount": 200,
"pageSize": 10,
"currentPage": 1,
"totalPages": 20
}
}
但是从这里要注意一旦我们对API响应进行自定义,那么就代表我们完全控制了要格式化数据的方式,同时丢失了默认API响应的某些选项配置。但是我们仍然可以利用ApiException()方法引发用户定义的错误消息
如下所示
[Route("{id:long}")]
[HttpPut]
public async Task<MyCustomApiResponse> Put(long id, [FromBody] PersonDTO dto)
{
if (ModelState.IsValid)
{
try
{
var person = _mapper.Map<Person>(dto);
person.ID = id;
if (await _personManager.UpdateAsync(person))
return new MyCustomApiResponse(DateTime.UtcNow, true, "Update successful.");
else
throw new ApiException($"Record with id: {id} does not exist.", 400);
}
catch (Exception ex)
{
_logger.Log(LogLevel.Error, ex, "Error when trying to update with ID:{@ID}", id);
throw;
}
}
else
throw new ApiException(ModelState.AllErrors());
}
现在当进行模型验证时,可以获得默认响应格式
{
"isError": true,
"responseException": {
"exceptionMessage": "Request responded with validation error(s). Please correct the specified validation errors and try again.",
"validationErrors": [
{
"field": "FirstName",
"message": "'First Name' must not be empty."
}
]
}
}
Reference
https://github.com/proudmonkey/AutoWrapper
ASP.NET Core AutoWrapper 自定义响应输出的更多相关文章
- ASP.NET Core中的响应压缩
介绍 响应压缩技术是目前Web开发领域中比较常用的技术,在带宽资源受限的情况下,使用压缩技术是提升带宽负载的首选方案.我们熟悉的Web服务器,比如IIS.Tomcat.Nginx.Apache ...
- asp.net core 中配合响应 html5 的音视频播放流,以及文件下载
一.asp.net core 中配合响应 html5 的音视频播放流,以及文件下载 问题描述: 目前测试了在 Windows(谷歌浏览器).Android(系统浏览器.QQ.微信).iOS 三个系统不 ...
- ASP.NET Core MVC – 自定义 Tag Helpers
ASP.NET Core Tag Helpers系列目录,共四篇: ASP.NET Core MVC Tag Helpers 介绍 ASP.NET Core MVC – Caching Tag Hel ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- ASP.NET Core Identity自定义数据库结构和完全使用Dapper而非EntityFramework Core
前言 原本本节内容是不存在的,出于有几个人问到了我:我想使用ASP.NET Core Identity,但是我又不想使用默认生成的数据库表,想自定义一套,我想要使用ASP.NE Core Identi ...
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- ASP.NET Core 中间件 自定义全局异常中间件以及 MVC异常过滤器作用
中间件是一种装配到应用管道以处理请求和响应的软件. 每个组件: 选择是否将请求传递到管道中的下一个组件. 可在管道中的下一个组件前后执行工作. 请求委托用于生成请求管道. 请求委托处理每个 HTTP ...
- ASP.NET Core - 实现自定义WebApi模型验证
Framework时代 在Framework时代,我们一般进行参数验证的时候,以下代码是非常常见的 [HttpPost] public async Task<JsonResult> Sav ...
- 【ASP.NET Core】自定义Session的存储方式
在开始今天的表演之前,老周先跟大伙伴们说一句:"中秋节快乐". 今天咱们来聊一下如何自己动手,实现会话(Session)的存储方式.默认是存放在分布式内存中.由于HTTP消息是无状 ...
随机推荐
- 状态模式(State)-设计模式
软件模式是将模式的一般概念应用于软件开发领域,即软件开发的 总体指导思路或参照样板.软件模式并非仅限于设计模式,还包括 架构模式.分析模式和过程模式等,实际上,在软件生存期的每一个阶段都存在着一些被认 ...
- Mongo Delete-19
数据初始化 db.inventory.insertMany( [ { item: "journal", qty: 25, size: { h: 14, w: 21, uom: &q ...
- Python计算给定日期的周内的某一天
先理一下思路:1.weekday会根据某个日期返回0到6的一个数字来表示星期几对吧,0==星期一我们来列一个表: [0,1,2,3,4,5,6] 2.知道了星期几之后,你可以计算出那一周相对于这个0到 ...
- Python2.7错误处理FileNotFoundError报错NameError: name 'FileNotFoundError' is not defined
错误信息如下: 原因是FileNotFoundError是python3.0中的写法,而Python2.7中应写为IOError.
- Python知识点汇总
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- 9——PHP循环结构foreach用法
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...
- Ubuntu 18.04 国内的 apt 源
一.Ubuntu 18.04 国内的 apt 源 1. 阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted univers ...
- win10下安装LoadRunner12汉化包
1.前提是已经下载LoadRunner安装文件,及已经安装成功: 安装包: 安装成功后,桌面会出现3个图标: 下面,开始安装汉化包: 1.右键点击“HP_LoadRunner_12.02_Commun ...
- [Python之路] object类中的特殊方法
一.object类的源码 python版本:3.8 class object: """ The most base type """ # d ...
- 它的JS与HTML标签是分离的吗
一个单的利用JS切换图片的功能写法1: <section> <h2>JS切换图片</h2> <ul class="pictable"> ...