Я пытаюсь создать единую обработку ошибок/отчетность в ASP.NET Web API 2.1 Проект, построенный поверх промежуточного ПО OWIN (IIS HOST с использованием Owin.Host.SystemWeb).
В настоящее время я использовал собственный журнал регистрации исключений, который наследует от 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"
}
Теперь это работает отлично, если какое-либо исключение происходит w в конвейере запроса контроллера Api.
Но в моей ситуации я использую промежуточное ПО Microsoft.Owin.Security.OAuth
для создания токенов-носителей, и это промежуточное программное обеспечение ничего не знает о обработке исключений веб-API, например, если в методе ValidateClientAuthentication
было выбрано исключение < мой NLogExceptionLogger
not 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", mt snot уверен, что это оптимальный способ сделать это.
2 - Теперь, когда я выполнил ведение журнала как на предыдущем шаге, я действительно не знаю, как изменить ответ исключения, поскольку мне нужно вернуть клиенту стандартную модель JSON для любого исключения, происходящего в "OAuthAuthorizationServerProvider". Существует связанный ответ здесь. Я пытался зависеть, но это не сработало.
Вот мой класс 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);
}
}
}