OWIN ミドルウェア (Owin.Host.SystemWeb を使用する IIS HOST) の上に構築された ASP.NET Web API 2.1 プロジェクトで、統一されたエラー処理/レポートを作成しようとしています。現在、NLog から継承して使用するカスタム例外ロガーをSystem.Web.Http.ExceptionHandling.ExceptionLogger
使用して、すべての例外を以下のコードとしてログに記録しました。
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
//Log using NLog
}
}
System.Web.Http.ExceptionHandling.ExceptionHandler
以下のコードを使用して、すべての API 例外の応答本文を、すべての例外の詳細を非表示にするわかりやすい統一応答に変更したいと考えています。
public class ContentNegotiatedExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
var errorDataModel = new ErrorDataModel
{
Message = "Internal server error occurred, error has been reported!",
Details = context.Exception.Message,
ErrorReference = context.Exception.Data["ErrorReference"] != null ? context.Exception.Data["ErrorReference"].ToString() : string.Empty,
DateTime = DateTime.UtcNow
};
var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, errorDataModel);
context.Result = new ResponseMessageResult(response);
}
}
これにより、例外が発生したときにクライアントに対して以下の応答が返されます。
{
"Message": "Internal server error occurred, error has been reported!",
"Details": "Ooops!",
"ErrorReference": "56627a45d23732d2",
"DateTime": "2015-12-27T09:42:40.2982314Z"
}
これで、Api Controller リクエスト パイプライン内で例外が発生した場合でも問題なく動作しています。
しかし、私の状況では、Microsoft.Owin.Security.OAuth
ベアラートークンを生成するためにミドルウェアを使用してValidateClientAuthentication
いNLogExceptionLogger
ますContentNegotiatedExceptionHandler
.それを処理しようとすると、私が使用したサンプルコードAuthorizationServerProvider
は次のとおりです。
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//Expcetion occurred here
int x = int.Parse("");
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.UserName != context.Password)
{
context.SetError("invalid_credentials", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
context.Validated(identity);
}
}
したがって、以下の2つの問題を実装する際のガイダンスをいただければ幸いです。
1 - OWIN ミドルウェアによって生成された例外のみを処理するグローバル例外ハンドラーを作成しますか? この回答に従って、例外処理用のミドルウェアを作成し、それを最初のものとして登録しました。「OAuthAuthorizationServerProvider」から発生した例外をログに記録できましたが、これが最適な方法であるかどうかはわかりません。
2 - 前のステップでロギングを実装したとき、「OAuthAuthorizationServerProvider」で発生した例外の標準 JSON モデルをクライアントに返す必要があるため、例外の応答を変更する方法がまったくわかりません。ここに依存しようとした関連する回答がありますが、うまくいきませんでした。
これが私の Startup クラスと、GlobalExceptionMiddleware
例外のキャッチ/ロギング用に作成したカスタムです。欠落している平和は、例外に対して統一された JSON 応答を返すことです。どんなアイデアでも大歓迎です。
public class Startup
{
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());
httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
app.Use<GlobalExceptionMiddleware>();
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(httpConfig);
}
}
public class GlobalExceptionMiddleware : OwinMiddleware
{
public GlobalExceptionMiddleware(OwinMiddleware next)
: base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
NLogLogger.LogError(ex, context);
}
}
}