溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ASP.NET Core AutoWrapper自定義響應(yīng)輸出的實(shí)現(xiàn)示例

發(fā)布時(shí)間:2021-02-04 16:04:01 來(lái)源:億速云 閱讀:159 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下ASP.NET Core AutoWrapper自定義響應(yīng)輸出的實(shí)現(xiàn)示例,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

前言

AutoWrapper是一個(gè)簡(jiǎn)單可自定義全局異常處理程序和ASP.NET Core API響應(yīng)的包裝。他使用ASP.NET Core middleware攔截傳入的HTTP請(qǐng)求,并將最后的結(jié)果使用統(tǒng)一的格式來(lái)自動(dòng)包裝起來(lái).目的主要是讓我們更多的關(guān)注業(yè)務(wù)特定的代碼要求,并讓包裝器自動(dòng)處理HTTP響應(yīng)。這可以在構(gòu)建API時(shí)加快開發(fā)時(shí)間,同時(shí)為HTTP響應(yīng)試試我們統(tǒng)一的標(biāo)準(zhǔn)。

安裝

AutoWrapper.Core從NuGet或通過(guò)CLI下載并安裝

PM> Install-Package AutoWrapper.Core

在Startup.cs Configure方法中注冊(cè)以下內(nèi)容,但是切記要放在UseRouting前

app.UseApiResponseAndExceptionWrapper();

啟動(dòng)屬性映射

默認(rèn)情況下AutoWrapper將在成功請(qǐng)求成功時(shí)輸出以下格式:

{
  "message": "Request successful.",
  "isError": false,
  "result": [
   {
    "id": 7002,
    "firstName": "Vianne",
    "lastName": "Durano",
    "dateOfBirth": "2018-11-01T00:00:00"
   }
  ]
}

如果說(shuō)不喜歡默認(rèn)屬性命名方式,那么我們可以通過(guò)AutoWrapperPropertyMap屬性進(jìn)行映射為我們需要指定的任何名稱。例如我么可以將result屬性的名稱更改為data。如下所示

public class MapResponseObject 
{
  [AutoWrapperPropertyMap(Prop.Result)]
  public object Data { get; set; }
}

然后將MapResponseObject類傳遞給AutpWrapper middleware

app.UseApiResponseAndExceptionWrapper<MapResponseObject>();

通過(guò)映射重新請(qǐng)求后,現(xiàn)在影響格式如下所示

{
  "message": "Request successful.",
  "isError": false,
  "data": {
    "id": 7002,
    "firstName": "Vianne",
    "lastName": "Durano",
    "dateOfBirth": "2018-11-01T00:00:00"
  }
}

可以從中看出result屬性已經(jīng)更換為data屬性了

默認(rèn)情況下AutoWrapper發(fā)生異常時(shí)將吐出以下響應(yīng)格式

{
  "isError": true,
  "responseException": {
    "exceptionMessage": "Unhandled Exception occurred. Unable to process the request."
  }
}

而且如果在AutoWrapperOptions中設(shè)置了IsDebug,則將產(chǎn)生帶有堆棧跟蹤信息的類似信息

{
  "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; }
}

通過(guò)如下代碼來(lái)模擬錯(cuò)誤

int num = Convert.ToInt32("10s");

現(xiàn)在映射后的輸出如下所示

{
  "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 …"
  }
}

請(qǐng)注意APIError現(xiàn)在根據(jù)MapResponseObject類中定義的屬性更改了模型的默認(rèn)屬性。

我們可以自由的選擇映射任何屬性,下面是映射屬性相對(duì)應(yīng)的列表

[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)]

自定義錯(cuò)誤架構(gòu)

AutoWrapper還提供了一個(gè)APIException可用于定義自己的異常的對(duì)象,如果想拋出自己的異常消息,則可以簡(jiǎn)單地執(zhí)行以下操作

throw new ApiException("Error blah", 400, "511", "http://blah.com/error/511");

默認(rèn)輸出格式如下所示

{
  "isError": true,
  "responseException": {
    "exceptionMessage": "Error blah",
    "referenceErrorCode": "511",
    "referenceDocumentLink": "http://blah.com/error/511"
  }
}

當(dāng)然我們可以自定義錯(cuò)誤格式

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;
  }
}

然后我們可以通過(guò)如下代碼進(jìn)行引發(fā)我們錯(cuò)誤

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響應(yīng)格式

如果映射滿足不了我們的需求。并且我們需要向API響應(yīng)模型中添加其他屬性,那么我們現(xiàn)在可以自定義自己的格式類,通過(guò)設(shè)置UseCustomSchema為true來(lái)實(shí)現(xiàn),代碼如下所示

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

現(xiàn)在假設(shè)我們想在主API中響應(yīng)中包含一個(gè)屬性SentDate和Pagination對(duì)象,我們可能希望將API響應(yīng)模型定義為以下格式

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; }
}

通過(guò)如下代碼片段進(jìn)行測(cè)試結(jié)果

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
    });

}

運(yùn)行后會(huì)得到如下影響格式

{
  "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
  }
}

但是從這里要注意一旦我們對(duì)API響應(yīng)進(jìn)行自定義,那么就代表我們完全控制了要格式化數(shù)據(jù)的方式,同時(shí)丟失了默認(rèn)API響應(yīng)的某些選項(xiàng)配置。但是我們?nèi)匀豢梢岳肁piException()方法引發(fā)用戶定義的錯(cuò)誤消息

如下所示

[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());
}

現(xiàn)在當(dāng)進(jìn)行模型驗(yàn)證時(shí),可以獲得默認(rèn)響應(yīng)格式

{
  "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."
      }
    ]
  }
}

看完了這篇文章,相信你對(duì)“ASP.NET Core AutoWrapper自定義響應(yīng)輸出的實(shí)現(xiàn)示例”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI