ASP.NET Web API 2.0統一応答フォーマット
4955 ワード
従来の実装
Web APIサービスを構築する際、クライアントの要求に対して、私たちは一般的に応答するJSONフォーマットをカスタマイズします.例えば:
{
"Data" : {
"Id" : 100,
"Name" : "Robin"
},
"ErrorMessage" : " "
}
ASPに基づく.NET Web APIのアプリケーションでは、次のような構造のCクラスを作成します.
public class ApiResult
{
public string ErrorMessage { get; set; }
public object Data { get; set; }
}
ここで、ErrorMessageは空またはnullであり、異常がないことを示す.この場合、Dataは必要なデータである.逆に、ErrorMessageが空またはnullでない場合は、エラーメッセージを表し、Dataはnullになります.
次にActionでクラスのインスタンスを返します.Web APIでは、フォーマットを内部で呼び出して、次のようにオブジェクトをJSONまたはXMLなどのフォーマットにシーケンス化します.
public class UserController : ApiController
{
public IHttpActionResult GetUser()
{
return new ApiResult()
{
Data = new User{ Id = 100, Name = "Robin" },
ErrorMessage = string.Empty
};
}
}
public class User
{
public int Id {get; set;}
public string Name {get; set;}
}
はい、伝統的なやり方はこのようにして、実現することができます.しかしさらに考えると、非常に多くのアクション方法があれば、毎回reutrn new ApiResult(){......}と書きます.特に煩わしいのではないでしょうか.
に質問
Actionメソッドで本当に必要なデータだけを返す方法はありませんが、クライアントに返すときに約束のJSON構造に統一されるのでしょうか.
ソリューション
もちろん、Web APIが提供するActionFilterを利用すれば実現できる.
まず、CustomActionFilterを新規作成します.
public class CustomActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext context)
{
var content = context.Response?.Content as ObjectContent;
if (content != null)
{
content.Value = new ApiResult
{
Data = content.Value,
};
}
}
}
アクションメソッドは次のように書きます.
public User GetAll()
{
return new new User{Id = 100, Name = "Robin"};
}
このような実装のもう1つの利点は、戻り値が強いタイプであるため、これに基づいてAPIドキュメントを生成することができ、方法の可読性もより良いことである.
例外処理
前述した需要が実現し、異常をどのように処理するかをさらに考慮します.コードBUGが未処理の例外を投げ出すため、Web APIは依然としてCustomActionFilterのコードを呼び出すが、この場合Response=nullとなりcontent.Valueは再割り当てされます.この場合、Web APIは、フレームワークで約束されたJSONメッセージをクライアントに返します.これは、Web APIが投げ出した未処理の例外メッセージです.
{
"Message": "An error has occurred.",
"ExceptionMessage": "No MessageException parameter",
"ExceptionType": "Framework.Common.MessageException",
"StackTrace": " Controllers.FooController.GetAll() ......
}
この場合、異常メッセージが業務約定のJSON形式に従うことを望む場合は、どうすればよいでしょうか.ここではいくつかの状況に分けます.
Action内の異常
CustomActionFilterのOnActionExecutedメソッドで直接処理でき、改造後のコードは以下の通りです.
public override void OnActionExecuted(HttpActionExecutedContext context)
{
var content = context.Response?.Content as ObjectContent;
if (content != null)
{
content.Value = new ApiResult { Data = content.Value };
}
//
if (context.Exception != null)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(JsonConvert.SerializeObject(
new ApiResult
{
ErrorMessage = context.Exception.Message
}), Encoding.UTF8, "application/json")
};
}
}
同様に、カスタムExceptionFilterを使用して同様の目的を達成することもできます.ここでは、コードを簡単に貼らないようにします.
その他の例外
ActionFilterAttributeとExceptionFilterAttributeは、Action内の異常などの一部の異常しか処理できませんが、例えば以下のような未処理の異常は、フィルタが助けられません.
Web APIは、グローバル範囲内の未処理例外を処理するために、ExceptionHandlerおよびExceptionLoggerを提供する.詳細は私が翻訳した文書:ASP.を参照してください.NET Web API 2におけるグローバルエラー処理では、未処理の例外をキャプチャして処理した後、応答メッセージを再設定できるのはExceptionHandlerのみであり、ExceptionLoggerはできない.
コードは次のとおりです.
public class CollectServiceExceptionHandler : ExceptionHandler
{
public override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
context.Result = new ApiResult { ErrorMessage = context.Exception.Message };
return base.HandleAsync(context, cancellationToken);
}
}
注意:ここでExceptionHandlerContextのResult属性のタイプはIHttpActionResultなので、ApiResultクラスはIHttpActionResultインタフェースを実装します.
ExceptionHandlerの目的は、グローバル範囲内で処理されていない例外を受信し、カスタムエラーメッセージを返すことです.
まとめ
冒頭のニーズを実現するには、3つの実現方法があります.
転載先:https://www.cnblogs.com/songxingzheng/p/6423697.html