ASP.NET Core AutoWrapper 自定义响应输出实现

 更新时间:2021年9月22日 09:59  点击:1938

前言

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 AutoWrapper响应输出内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • ASP.NET购物车实现过程详解

    这篇文章主要为大家详细介绍了ASP.NET购物车的实现过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
  • .NET Core下使用Kafka的方法步骤

    这篇文章主要介绍了.NET Core下使用Kafka的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 在ASP.NET 2.0中操作数据之七十二:调试存储过程

    在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
  • 详解.NET Core 3.0 里新的JSON API

    这篇文章主要介绍了详解.NET Core 3.0 里新的JSON API,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • ASP.NET Core根据环境变量支持多个 appsettings.json配置文件

    这篇文章主要介绍了ASP.NET Core根据环境变量支持多个 appsettings.json配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 记一次EFCore类型转换错误及解决方案

    这篇文章主要介绍了记一次EFCore类型转换错误及解决方案,帮助大家更好的理解和学习使用asp.net core,感兴趣的朋友可以了解下...2021-09-22
  • 详解ASP.NET Core 中基于工厂的中间件激活的实现方法

    这篇文章主要介绍了ASP.NET Core 中基于工厂的中间件激活的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • asp.net通过消息队列处理高并发请求(以抢小米手机为例)

    这篇文章主要介绍了asp.net通过消息队列处理高并发请求(以抢小米手机为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • Underscore源码分析

    Underscore 是一个 JavaScript 工具库,它提供了一整套函数式编程的实用功能,但是没有扩展任何 JavaScript 内置对象。这篇文章主要介绍了underscore源码分析相关知识,感兴趣的朋友一起学习吧...2016-01-02
  • ASP.NET单选按钮控件RadioButton常用属性和方法介绍

    RadioButton又称单选按钮,其在工具箱中的图标为 ,单选按钮通常成组出现,用于提供两个或多个互斥选项,即在一组单选钮中只能选择一个...2021-09-22
  • ASP.NET 2.0中的数据操作:使用两个DropDownList过滤的主/从报表

    在前面的指南中我们研究了如何显示一个简单的主/从报表, 该报表使用DropDownList和GridView控件, DropDownList填充类别,GridView显示选定类别的产品. 这类报表用于显示具有...2016-05-19
  • 详解.NET Core 使用HttpClient SSL请求出错的解决办法

    这篇文章主要介绍了.NET Core 使用HttpClient SSL请求出错的解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
  • ASP.NET中iframe框架点击左边页面链接 右边显示链接页面内容

    这篇文章主要介绍了ASP.NET中iframe框架点击左边页面链接,右边显示链接页面内容的实现代码,感兴趣的小伙伴们可以参考一下...2021-09-22
  • 创建一个完整的ASP.NET Web API项目

    ASP.NET Web API具有与ASP.NET MVC类似的编程方式,ASP.NET Web API不仅仅具有一个完全独立的消息处理管道,而且这个管道比为ASP.NET MVC设计的管道更为复杂,功能也更为强大。下面创建一个简单的Web API项目,需要的朋友可以参考下...2021-09-22
  • ASP.NET连接MySql数据库的2个方法及示例

    这篇文章主要介绍了ASP.NET连接MySql数据库的2个方法及示例,使用的是MySQL官方组件和ODBC.NET,需要的朋友可以参考下...2021-09-22
  • Asp.Net使用Bulk实现批量插入数据

    这篇文章主要介绍了Asp.Net使用Bulk实现批量插入数据的方法,对于进行asp.net数据库程序设计非常有借鉴价值,需要的朋友可以参考下...2021-09-22
  • Asp.net中获取DataTable选择第一行某一列值

    这篇文章主要介绍了获取DataTable选择第一行某一列值,需要的朋友可以参考下...2021-09-22
  • Asp.net动态生成html页面的方法分享

    这篇文章介绍了Asp.net动态生成html页面的方法,有需要的朋友可以参考一下...2021-09-22
  • ASP.Net中的async+await异步编程的实现

    这篇文章主要介绍了ASP.Net中的async+await异步编程的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • .net EF Core专题:EF Core 读取数据时发生了什么?

    这篇文章主要介绍了EF Core 读取数据的的相关知识,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2021-09-22