【发布时间】:2016-04-01 11:21:19
【问题描述】:
我正在尝试在基于 OWIN 中间件(使用 Owin.Host.SystemWeb 的 IIS HOST)之上构建的 ASP.NET Web API 2.1 项目中创建统一的错误处理/报告。
目前我使用了一个自定义异常记录器,它继承自System.Web.Http.ExceptionHandling.ExceptionLogger,并使用 NLog 记录所有异常,如下代码:
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
//Log using NLog
}
}
我想将所有 API 异常的响应正文更改为友好的统一响应,该响应使用 System.Web.Http.ExceptionHandling.ExceptionHandler 隐藏所有异常详细信息,代码如下:
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 控制器请求管道中发生任何异常,这一切都很好。
但在我的情况下,我使用中间件 Microsoft.Owin.Security.OAuth 来生成不记名令牌,而这个中间件对 Web API 异常处理一无所知,例如,如果在方法 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 中间件生成的异常的全局异常处理程序?我关注this answer 并创建了一个用于异常处理的中间件并将其注册为第一个中间件,我能够记录源自“OAuthAuthorizationServerProvider”的异常,但我不确定这是否是最佳方式。
2 - 现在,当我在上一步中实现日志记录时,我真的不知道如何更改异常的响应,因为我需要向客户端返回标准 JSON 模型,以应对“ OAuthAuthorizationServerProvider”。有一个相关的 answer here 我试图依赖但它没有用。
这是我的 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);
}
}
}
【问题讨论】:
-
可以直接在中间件(response.write)中写入响应。如果您想使用其他方法,请检查 global.asax Application_Error
标签: asp.net-web-api asp.net-web-api2 owin katana owin-middleware