目录

介绍

默认的ASP.NET Core API响应

AutoWrapper.Core的救援

主要特点:

TL,DR 给我看代码

定义自己的自定义消息

定义自己的Api异常

选项

版本1.0.0

1.1.0版添加

支持日志

支持Swagger

总结

GitHub Repo

参考文献


介绍

在为“实际”应用程序项目构建API时,大多数开发人员忘记了向其消费者提供有意义的响应的重要性。发生这种情况有几个原因;可能是他们的开发时间有限,他们没有标准的HTTP 响应格式,或者只是只要API 将所需的数据返回给消费者,他们就不在乎响应。嗯,API不仅要通过 HTTP传递JSON ,还应如何向使用它的开发人员提出有意义的响应。

就像有人曾经说过的…

一个好的API设计是使用它的开发人员的UX

作为重视消费者的API 开发者,我们希望对他们做出有意义且一致的API响应。

ASP.NET Core 使我们能够快速创建REST API。但是,对于开箱即用的成功请求和错误,它们不会提供一致的响应。如果你对API采用RESTful方式,那么你将被使用HTTP动词,如GET、POST、PUT和DELETE。根据您的方法/操作的设计方式,每个操作都可能返回不同的类型。你的POST、PUT和DELETE终端可能会返回一个数据,或者根本没有。您的GET终端可能返回一个 string、 List<T>、某种类型的IEnumerable ,甚至是一个object。另一方面,如果您的API 抛出错误,它将返回一个object 或更糟糕的指出错误原因的 HTML 字符串。所有这些响应之间的差异使得使用API​​变得很困难,因为使用者需要了解每种情况下返回的数据的类型和结构。客户代码和服务代码都变得难以管理。

去年,我创建了两个用于管理异常和响应一致性的Nuget 包,使用一个自定义的用于restful API 的object包装器。

令我惊讶的是,这两个软件包现在都有数百次下载,并且被Blazor Boilerplate等其他开源项目使用。

虽然我认为这两个软件包都成功,但它们仍然存在一些故障,因此我决定创建一个新软件包来重构代码库,应用错误修复并为其添加新功能。

在本文中,我们将研究如何使用AutoWrapper来美化我们的ASP.NET Core  API响应。

默认的ASP.NET Core API响应

当您创建新的ASP.NET Core API模板时,Visual Studio将构建所有必需的文件和依赖项,以帮助您开始构建RESTful API。生成的模板包含一个“WeatherForecastController”,用于使用静态数据模拟简单的GET请求,如以下代码所示:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{private static readonly string[] Summaries = new[]{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};private readonly ILogger<WeatherForecastController> _logger;public WeatherForecastController(ILogger<WeatherForecastController> logger){_logger = logger;}[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();}
}

运行应用程序时,将以JSON格式显示以下输出:

[{"date": "2019-09-16T13:08:39.5994786-05:00","temperatureC": -8,"temperatureF": 18,"summary": "Bracing"},{"date": "2019-09-17T13:08:39.5995153-05:00","temperatureC": 54,"temperatureF": 129,"summary": "Cool"},{"date": "2019-09-18T13:08:39.5995162-05:00","temperatureC": 33,"temperatureF": 91,"summary": "Bracing"},{"date": "2019-09-19T13:08:39.5995166-05:00","temperatureC": 38,"temperatureF": 100,"summary": "Balmy"},{"date": "2019-09-20T13:08:39.599517-05:00","temperatureC": -3,"temperatureF": 27,"summary": "Sweltering"}
]

太好了,其API的工作与我们期望的一样,只是它没有给我们带来有意义的回应。我们知道数据是响应中非常重要的部分,但是,随便吐出数据是因为JSON响应实际上并没有太大帮助,尤其是当每个请求之间发生意外行为时。

例如,以下代码模拟了您的代码中可能发生的意外错误:

//This is just an idiot example to trigger an error
int num = Convert.ToInt32("a");

上面的代码尝试将包含非数字值的string转换为integer类型,这将在运行时导致错误。响应输出看起来像这样:

1:未处理的异常

你能想象那些使用你的API从响应中看到这种格式的开发人员的失望吗?至少堆栈跟踪信息很有用,因为它可以使您了解错误的原因,但是应该进行处理,并且永远不要让您的API使用者看到该信息有安全隐患。堆栈跟踪信息在开发阶段和调试过程中绝对有帮助。在生产中,应处理此类详细错误,将其记录在某处进行分析,然后将有意义的响应返回给消费者。

另一种情况是,当您尝试访问 不存在的API终端时,除了著名的404 (Not Found) Http状态代码以外,没有任何回应。

使用REST API时,重要的是处理异常并为API处理的所有请求返回一致的响应,无论成功或失败。这使得使用API​​变得容易得多,而无需在客户端上使用复杂的代码。

AutoWrapper.Core的救援

AutoWrapper 会处理传入的  HTTP 请求,并通过为成功和错误结果提供一致的响应格式来自动为您包装响应。目的是让您专注于特定于业务的需求,并由包装程序处理HTTP 响应。想象一下在执行HTTP 响应标准时,您在开发API上节省的时间。

AutoWrapper 是基于VMD.RESTApiResponseWrapper.Core的项目分支  ,旨在支持.NET Core 3.x及更高版本。对该程序包的实现进行了重构,以提供更方便的方式来使用中间件,从而增加了灵活性。

主要特点:

  • 异常处理
  • ModelState验证错误处理(同时支持数据注释和FluentValidation)
  • 可配置的API异常
  • 结果和错误的一致响应格式
  • 详细的结果回复
  • 详细的错误响应
  • 可配置的HTTP状态码和消息
  • 添加对Swagger的支持
  • 添加对请求、响应和异常的日志支持
  • 在中间件中添加选项以设置ApiVersion和IsDebug属性

TL,DR 给我看代码

仅需几步,您就可以将API Controller转换为返回一些有意义的响应,而无需付出很多开发工作。您要做的就是:

1. 从NuGet或通过CLI 下载并安装最新版本的AutoWrapper.Core:

PM> Install-Package AutoWrapper.Core -Version 1.0.1-rc

引用:

注意:目前,这是一个预发行版本,一旦.NET Core 3发布,它将正式发行。

2.在Startup.cs中声明以下名称空间

using AutoWrapper;

3.在UseRouting()中间件“之前”的Startup.cs的Configure()方法中注册下面的中间件:

app.UseApiResponseAndExceptionWrapper();

默认的API版本格式设置为“ 1.0.0.0”。如果希望为API指定其他版本格式,则可以执行以下操作:

app.UseApiResponseAndExceptionWrapper(new ApiResponseOptions { ApiVersion = "2.0" });

很简单!现在,尝试再次构建并运行ASP.NET Core API默认应用程序。根据我们的示例,以下是“WeatherForecastController” API 响应的样子:

{"message": "Request successful.","isError": false,"result": [{"date": "2019-09-16T23:37:51.5544349-05:00","temperatureC": 21,"temperatureF": 69,"summary": "Mild"},{"date": "2019-09-17T23:37:51.554466-05:00","temperatureC": 28,"temperatureF": 82,"summary": "Cool"},{"date": "2019-09-18T23:37:51.554467-05:00","temperatureC": 21,"temperatureF": 69,"summary": "Sweltering"},{"date": "2019-09-19T23:37:51.5544676-05:00","temperatureC": 53,"temperatureF": 127,"summary": "Chilly"},{"date": "2019-09-20T23:37:51.5544681-05:00","temperatureC": 22,"temperatureF": 71,"summary": "Bracing"}]
}

如果您注意到了,那么输出现在在响应中包含一些属性,例如message,isError以及在result属性中包含的实际数据。

关于AutoWrapper的另一个好处是,日志记录已经预先配置。默认情况下,.NET Core应用程序具有内置的日志记录机制,并且包装程序已拦截的所有请求和响应都将被自动记录。对于此示例,它将在Visual Studio控制台窗口中显示如下内容:

2Visual Studio控制台日志

.NET Core支持与各种内置和第三方日志记录提供程序一起使用的日志记录API。根据您使用哪种受支持的.NET Core日志记录提供程序以及如何配置记录数据的位置(例如,文本文件,Cloud等),AutoWrapper会自动为您写入日志。

这是当您尝试指向不存在的URL时的另一个输出示例:

{"isError": true,"responseException": {"exceptionMessage": "Request not found. The specified uri does not exist.","details": null,"referenceErrorCode": null,"referenceDocumentLink": null,"validationErrors": null}
}

现在注意到响应对象是如何更改的。statusCode自动设置为404。当已经发生任何意外错误或异常时,result属性将自动省略,而显示responseException属性以显示错误消息和额外信息。

请记住,任何错误或异常也将被记录。例如,如果我们再次运行以下代码:

//This is just an idiot example to trigger an error
int num = Convert.ToInt32("a");

现在它将给您以下响应:

{"isError": true,"responseException": {"exceptionMessage": "Unhandled Exception occured. Unable to process the request.","details": null,"referenceErrorCode": null,"referenceDocumentLink": null,"validationErrors": null}
}

控制台窗口将显示以下内容:

3Visual Studio控制台日志

默认情况下,AutoWrapper禁止显示堆栈跟踪信息。如果要在开发阶段从响应中查看错误的实际详细信息,只需将AutoWrapperOptions IsDebug设置为true:

app.UseApiResponseAndExceptionWrapper( new AutoWrapperOptions { IsDebug = true });

现在,当您再次运行该应用程序以触发异常时,它将显示如下内容:

{"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   at System.Convert.ToInt32(String value)\r\n   at AutoWrapperDemo.Controllers.WeatherForecastController.Get() in . . . . . . .,"referenceErrorCode": null,"referenceDocumentLink": null,"validationErrors": null}
}

注意,现在显示了真正的异常消息及其详细信息。

定义自己的自定义消息

要在响应中显示自定义消息,请使用AutoWrapper.Wrappers命名空间中的ApiResponse对象。例如,如果要在成功POST完成后显示一条消息,则可以执行以下操作:

[HttpPost]
public async Task<ApiResponse> Post([FromBody]CreateBandDTO band)
{//Call a method to add a new record to the databasetry{var result = await SampleData.AddNew(band);return new ApiResponse("New record has been created to the database", result, 201);}catch (Exception ex){//TO DO: Log exthrow;}
}

成功运行代码将为您提供以下结果:

{"message": "New record has been created to the database","isError": false,"result": 100
}

ApiResponse对象具有可以设置的以下参数:

ApiResponse(string message, object result = null, int statusCode = 200, string apiVersion = "1.0.0.0")

定义自己的Api异常

AutoWrapper还提供了可用于定义自己的异常的ApiException对象。例如,如果您想抛出自己的异常消息,则可以简单地执行以下操作:

用于捕获ModelState验证错误

throw new ApiException(ModelState.AllErrors());

用于抛出您自己的异常消息

throw new ApiException($"Record with id: {id} does not exist.", 400);

例如,让我们使用ModelState验证来修改POST方法:

[HttpPost]
public async Task<ApiResponse> Post([FromBody]CreateBandDTO band)
{if (ModelState.IsValid){//Call a method to add a new record to the databasetry{var result = await SampleData.AddNew(band);return new ApiResponse("New record has been created to the database", result, 201);}catch (Exception ex){//TO DO: Log exthrow;}}elsethrow new ApiException(ModelState.AllErrors());
}

验证失败时,运行代码将导致如下所示:

{"isError": true,"responseException": {"exceptionMessage": "Request responded with validation error(s). Please correct the specified validation errors and try again.","details": null,"referenceErrorCode": null,"referenceDocumentLink": null,"validationErrors": [{"field": "Name","message": "The Name field is required."}]}
}

查看如何使用模型中的违规字段自动填充validationErrors属性。

ApiException对象包含以下三个重载constructors,可用于定义异常:

ApiException(string message, int statusCode = 500, string errorCode = "", string refLink = "")
ApiException(IEnumerable<ValidationError> errors, int statusCode = 400)
ApiException(System.Exception ex, int statusCode = 500)

选项

以下属性是可以设置的选项:

版本1.0.0

  • ApiVersion
  • ShowApiVersion
  • ShowStatusCode
  • IsDebug

1.1.0版添加

  • IsApiOnly
  • WrapWhenApiPathStartsWith

ShowApiVersion

如果要 在响应中显示API版本,则可以执行以下操作:

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { ShowApiVersion = true });

默认API 版本格式设置为“ 1.0.0.0”

ApiVersion

如果您希望指定其他版本格式,则可以执行以下操作:

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { ShowApiVersion = true, ApiVersion = "2.0"
});

ShowStatusCode

如果要在响应中显示StatusCode,则可以执行以下操作:

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { ShowStatusCode = true });

IsDebug

默认情况下,AutoWrapper 禁止显示堆栈跟踪信息。如果要在开发阶段从响应中查看错误的实际详细信息,只需将设置AutoWrapperOptions IsDebug 为  true:

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { IsDebug = true }); 

IsApiOnly

AutoWrapper 仅可用于ASP.NET Core API项目模板。如果要在前端项目(如Angular、MVC、React、Blazor和其他支持.NET Core的SPA框架)中组合API Controllers ,请使用此属性启用它。

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { IsApiOnly = false} );

WrapWhenApiPathStartsWith

如果将IsApiOnly 选项设置为false,则还可以指定API 路径段以进行验证。默认情况下,它设置为"/api"。如果要将其设置为其他内容,则可以执行以下操作:

app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { IsApiOnly = false, WrapWhenApiPathStartsWith = "/myapi"
});

当请求路径包含WrapWhenApiPathStartsWith值时,这将激活AutoWrapper 来拦截HTTP响应。

引用:

请注意,我仍然建议您在一个单独的项目中实现API Controllers,以重视关注点的分离,并避免为您的SPAs和API混合路由配置。

支持日志

AutoWrapper 另一个好处是,日志记录已经预先配置。.NET Core应用程序默认情况下具有内置的日志记录机制,并且包装程序已拦截的所有请求和响应都将被自动记录(由于依赖倒置!)。.NET Core支持API与各种内置和第三方日志记录提供程序一起使用的日志记录。根据您使用哪种受支持的.NET Core日志记录提供程序以及如何配置记录数据的位置(例如,文本文件,Cloud等),AutoWrapper会自动为您写入日志。

支持Swagger

Swagger为您的API提供了高级文档,使开发人员可以参考您的API端点的详细信息并在必要时进行测试。这是非常有用的,特别是当您API是公开的并且希望许多开发人员使用它时。

AutoWrapper省略url中带有“/swagger”的任何请求,这样您仍然可以导航到Swagger UI以获得您的API文档。

总结

在本文中,我们学习了如何在您的ASP.NET Core应用程序中集成和使用AutoWrapper的核心功能。

我敢肯定,这个项目还有很多地方需要改进,请随时尝试一下,让我知道您的想法。

GitHub Repo

https://github.com/proudmonkey/AutoWrapper

参考文献

  • ASP.NET Core中间件
  • AutoWrapper.Core
  • ASP.NET Core 2.1:将VMD.RESTApiResponseWrapper.Core集成到REST API应用程序
  • ASP.NET Core和Web API:用于管理异常和一致响应的自定义包装器

AutoWrapper:通过有意义的响应来美化您的ASP.NET Core API相关推荐

  1. ASP.NET Core和Web API:用于管理异常和一致响应的自定义包装器

    目录 介绍 为什么? 怎么做? VMD.RESTApiResponseWrapper Nuget软件包 安装及使用 ASP.NET Core集成 ASP.NET Web API集成 样本响应输出 定义 ...

  2. 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的...

    学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听.接收和响应请求的 原文:学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一 ...

  3. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  4. symfony api 错误响应_如何设计一个牛逼的 API 接口

    在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...

  5. ASP.NET Web API 记录请求响应数据到日志的一个方法

    原文:ASP.NET Web API 记录请求响应数据到日志的一个方法 原文:http://blog.bossma.cn/dotnet/asp-net-web-api-log-request-resp ...

  6. ASP.NET Core自定义响应内容

    问题 在业务开发中,对Web API的返回格式有一定要求,需要是定制化的Json结构,用于前端统一处理: {Status : 0,Message: "",Info : xxx } ...

  7. ASP.NET Core中的响应压缩

    介绍 响应压缩技术是目前Web开发领域中比较常用的技术,在带宽资源受限的情况下,使用压缩技术是提升带宽负载的首选方案.我们熟悉的Web服务器,比如IIS.Tomcat.Nginx.Apache等都可以 ...

  8. 通过极简模拟框架让你了解ASP.NET Core MVC框架的设计与实现[中篇]:请求响应

    <200行代码,7个对象--让你了解ASP.NET Core框架的本质>让很多读者对ASP.NET Core管道有了真实的了解.在过去很长一段时间中,有很多人私信给我:能否按照相同的方式分 ...

  9. asp.net core 系列之Performance的 Response compression(响应压缩)

    本文,帮助了解响应压缩的一些知识及用法(大部分翻译于官网,英文水平有限,不准确之处,欢迎指正). 什么是响应压缩?响应压缩简单的说就是为了减少网络带宽,而把返回的响应压缩,使之体积缩小,从而加快响应的 ...

最新文章

  1. TCP 和 UDP 在socket编程中的区别
  2. java axisclient超时_调用webservice接口超时
  3. 在Intellij IDEA中运行Vaadin应用
  4. ole db 错误 通讯链接失败_西门子PLC1200的S7通讯(同一项目下)--GET接收指令
  5. IntelliJ IDEA 内存优化最佳实践
  6. java jslider 自定义_Java自定义JSlider UI
  7. VLAN 间 路由——华为(单臂路由)
  8. Vue.js 2.0从入门到放弃---入门实例(二)
  9. 数据结构与算法实验:实验二 链表实现一元多项式的加法/减法/乘法/求导
  10. LeetCode 739. 每日温度(java实现)
  11. windows 检测硬盘读写速度
  12. 决策树的特性及优缺点
  13. 【一些好听的英文歌曲】
  14. 磁共振检查头部能检测出什么_磁共振检查头部的注意事项
  15. 酒店点菜系统c语言,求一个用最基础的C语言编写的简单饭店点菜系统
  16. 软件的「向前兼容」和「向后兼容」
  17. wordpress建站准备教程(一)域名:域名备案、域名注册、域名绑定、域名解析
  18. 2022.1.17 学习笔记 (SPN中业务是如何传输的,主要是业务切片的调度编排)
  19. 十键调光调色智能台灯方案
  20. 去除百度地图的兴趣点和文字

热门文章

  1. matlab神经网络 误差曲线,神经网络如何输出各层训练误差曲线?
  2. pythonos模块介绍_python的os模块fnmatch模块介绍
  3. img src 本地图片_Java爬取简单的网页内容和图片
  4. 高质量壁纸网站,满足壁纸控的所有想象!
  5. 设计灵感|C4D卡通角色设计作品,你想要的模型集设都有
  6. 百搭手绘卡通牛年吉祥生肖素材,萌到心里的小牛
  7. 设计灵感|延展画面的插画Banner设计!
  8. 简约几何艺术海报PSD分层模板,即使简单也足以控制观众的注意力。
  9. 电商促销插画风PSD分层模板,直击底价!吸睛容情!
  10. Virtio: An I/O virtualization framework for Linux