ASP.NET Core AutoWrapper 自定義響應(yīng)輸出實(shí)現(xiàn)
前言
AutoWrapper是一個(gè)簡單可自定義全局異常處理程序和ASP.NET Core API響應(yīng)的包裝。他使用ASP.NET Core middleware攔截傳入的HTTP請求,并將最后的結(jié)果使用統(tǒng)一的格式來自動(dòng)包裝起來.目的主要是讓我們更多的關(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或通過CLI下載并安裝
PM> Install-Package AutoWrapper.Core
在Startup.cs Configure方法中注冊以下內(nèi)容,但是切記要放在UseRouting前
app.UseApiResponseAndExceptionWrapper();
啟動(dòng)屬性映射
默認(rèn)情況下AutoWrapper將在成功請求成功時(shí)輸出以下格式:
{
"message": "Request successful.",
"isError": false,
"result": [
{
"id": 7002,
"firstName": "Vianne",
"lastName": "Durano",
"dateOfBirth": "2018-11-01T00:00:00"
}
]
}
如果說不喜歡默認(rèn)屬性命名方式,那么我們可以通過AutoWrapperPropertyMap屬性進(jìn)行映射為我們需要指定的任何名稱。例如我么可以將result屬性的名稱更改為data。如下所示
public class MapResponseObject
{
[AutoWrapperPropertyMap(Prop.Result)]
public object Data { get; set; }
}
然后將MapResponseObject類傳遞給AutpWrapper middleware
app.UseApiResponseAndExceptionWrapper<MapResponseObject>();
通過映射重新請求后,現(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; }
}
通過如下代碼來模擬錯(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 …"
}
}
請注意APIError現(xiàn)在根據(jù)MapResponseObject類中定義的屬性更改了模型的默認(rèn)屬性。
我們可以自由的選擇映射任何屬性,下面是映射屬性相對應(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可用于定義自己的異常的對象,如果想拋出自己的異常消息,則可以簡單地執(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;
}
}
然后我們可以通過如下代碼進(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)在可以自定義自己的格式類,通過設(shè)置UseCustomSchema為true來實(shí)現(xiàn),代碼如下所示
app.UseApiResponseAndExceptionWrapper(new AutoWrapperOptions { UseCustomSchema = true });
現(xiàn)在假設(shè)我們想在主API中響應(yīng)中包含一個(gè)屬性SentDate和Pagination對象,我們可能希望將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; }
}
通過如下代碼片段進(jìn)行測試結(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)行后會得到如下影響格式
{
"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響應(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."
}
]
}
}
Reference
https://github.com/proudmonkey/AutoWrapper
到此這篇關(guān)于ASP.NET Core AutoWrapper 自定義響應(yīng)輸出實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)ASP.NET Core AutoWrapper響應(yīng)輸出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
DataGridView中綁定DataTable數(shù)據(jù)及相關(guān)操作實(shí)現(xiàn)代碼
DataGridView中綁定DataTable數(shù)據(jù)及相關(guān)操作2010-02-02
DataGridView - DataGridViewCheckBoxCell的使用介紹
Datagridview是.net中最復(fù)雜的控件,Datagridview中,用戶可以對行、列、單元格進(jìn)行編程,下面與大家分享下DataGridViewCheckBoxCell的使用,感興趣的朋友可以參考下哈2013-06-06
.NET中利用js讓子窗體向父頁面?zhèn)髦档膶?shí)現(xiàn)方法
.NET中利用js讓子窗體向父頁面?zhèn)髦档膶?shí)現(xiàn)方法,需要的朋友可以參考一下2013-02-02
根據(jù)Eval()函數(shù)綁定的值,來顯示GridView中的控件的方法
根據(jù)Eval()函數(shù)綁定的值,來顯示GridView中的控件的方法,需要的朋友可以參考一下2013-03-03
.Net Core中自定義認(rèn)證實(shí)現(xiàn)
本文主要介紹了.Net Core中自定義認(rèn)證實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
.net MVC 連接數(shù)據(jù)本地?cái)?shù)據(jù)庫三種方法總結(jié)
這篇文章主要介紹了.net MVC 連接數(shù)據(jù)本地?cái)?shù)據(jù)庫三種方法總結(jié)的相關(guān)資料,這里附有代碼實(shí)例,需要的朋友可以參考下2016-12-12

