ASP.NET Core 2.2 上的中间件 运行 中是否有任何方法可以检测请求是否针对 ApiController?
Is there any way within middleware running on ASP.NET Core 2.2 to detect if the request is for an ApiController?
我有一个应用程序在 ASP.NET Core 2.2 中同时具有 MVC 和 'new' ApiController 端点。
在添加 API 端点之前,我一直在使用注册为中间件的全局异常处理程序,使用 app.UseExceptionHandler((x) => { ... }
会重定向到错误页面。
当然,这不适用于 API 响应,我想 return 一个 ObjectResult
(协商)500
结果 ProblemDetails
格式化结果.
问题是,我不确定如何在我的 'UseExceptionHandler' lambda 中可靠地确定我是在处理 MVC 还是 API 请求。我可以使用某种请求 URL 匹配(例如 /api/...
前缀),但我想要一个更强大的解决方案,以后不会再回来咬我了。
我要实现的粗略伪代码版本是:
app.UseExceptionHandler(x =>
{
x.Run(async context =>
{
// extract the exception that was thrown
var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
try
{
// generically handle the exception regardless of what our response needs to look like by logging it
// NOTE: ExceptionHandlerMiddleware itself will log the exception
// TODO: need to find a way to see if we have run with negotiation turned on (in which case we are API not MVC!! see below extensions for clues?)
// TODO: ... could just use "/api/" prefix but that seems rubbish
if (true)
{
// return a 500 with object (in RFC 7807 form) negotiated to the right content type (eg. json)
}
else
{
// otherwise, we handle the response as a 500 error page redirect
}
}
catch (Exception exofex)
{
// NOTE: absolutely terrible if we get into here
log.Fatal($"Unhandled exception in global error handler!", exofex);
log.Fatal($"Handling exception: ", ex);
}
});
});
}
有什么想法吗?
干杯!
这可能与您的预期略有不同,但您可以检查该请求是否为 AJAX 请求。
您可以使用此扩展程序:
public static class HttpRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
if (request.Headers == null)
return false;
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
}
然后中间件的调用方法如下所示:
public async Task Invoke(HttpContext context)
{
if (context.Request.IsAjaxRequest())
{
try
{
await _next(context);
}
catch (Exception ex)
{
//Handle the exception
await HandleExceptionAsync(context, ex);
}
}
else
{
await _next(context);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
//you can do more complex logic here, but a basic example would be:
var result = JsonConvert.SerializeObject(new { error = "An unexpected error occurred." });
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
return context.Response.WriteAsync(result);
}
有关更详细的版本,请参阅 。
如果你想检查请求是否被路由到 ApiController
,你可以尝试 IExceptionFilter
来处理异常。
public class CustomExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (IsApi(context))
{
HttpStatusCode status = HttpStatusCode.InternalServerError;
var message = context.Result;
//You can enable logging error
context.ExceptionHandled = true;
HttpResponse response = context.HttpContext.Response;
response.StatusCode = (int)status;
response.ContentType = "application/json";
context.Result = new ObjectResult(new { ErrorMsg = message });
}
else
{
}
}
private bool IsApi(ExceptionContext context)
{
var controllerActionDesc = context.ActionDescriptor as ControllerActionDescriptor;
var attribute = controllerActionDesc
.ControllerTypeInfo
.CustomAttributes
.FirstOrDefault(c => c.AttributeType == typeof(ApiControllerAttribute));
return attribute == null ? false : true;
}
}
感谢其他人的所有建议,但经过更多的思考和想法后,我意识到我的方法一开始就不对——我应该在控制器中本地处理大多数异常并从那里回应。
我的错误处理中间件基本上与处理 MVC 未处理异常的方式相同。客户端将获得带有 HTML 响应的 500,但此时客户端无能为力,所以不会造成伤害。
感谢您的帮助!
我有一个应用程序在 ASP.NET Core 2.2 中同时具有 MVC 和 'new' ApiController 端点。
在添加 API 端点之前,我一直在使用注册为中间件的全局异常处理程序,使用 app.UseExceptionHandler((x) => { ... }
会重定向到错误页面。
当然,这不适用于 API 响应,我想 return 一个 ObjectResult
(协商)500
结果 ProblemDetails
格式化结果.
问题是,我不确定如何在我的 'UseExceptionHandler' lambda 中可靠地确定我是在处理 MVC 还是 API 请求。我可以使用某种请求 URL 匹配(例如 /api/...
前缀),但我想要一个更强大的解决方案,以后不会再回来咬我了。
我要实现的粗略伪代码版本是:
app.UseExceptionHandler(x =>
{
x.Run(async context =>
{
// extract the exception that was thrown
var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
try
{
// generically handle the exception regardless of what our response needs to look like by logging it
// NOTE: ExceptionHandlerMiddleware itself will log the exception
// TODO: need to find a way to see if we have run with negotiation turned on (in which case we are API not MVC!! see below extensions for clues?)
// TODO: ... could just use "/api/" prefix but that seems rubbish
if (true)
{
// return a 500 with object (in RFC 7807 form) negotiated to the right content type (eg. json)
}
else
{
// otherwise, we handle the response as a 500 error page redirect
}
}
catch (Exception exofex)
{
// NOTE: absolutely terrible if we get into here
log.Fatal($"Unhandled exception in global error handler!", exofex);
log.Fatal($"Handling exception: ", ex);
}
});
});
}
有什么想法吗?
干杯!
这可能与您的预期略有不同,但您可以检查该请求是否为 AJAX 请求。
您可以使用此扩展程序:
public static class HttpRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequest request)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
if (request.Headers == null)
return false;
return request.Headers["X-Requested-With"] == "XMLHttpRequest";
}
}
然后中间件的调用方法如下所示:
public async Task Invoke(HttpContext context)
{
if (context.Request.IsAjaxRequest())
{
try
{
await _next(context);
}
catch (Exception ex)
{
//Handle the exception
await HandleExceptionAsync(context, ex);
}
}
else
{
await _next(context);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
//you can do more complex logic here, but a basic example would be:
var result = JsonConvert.SerializeObject(new { error = "An unexpected error occurred." });
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
return context.Response.WriteAsync(result);
}
有关更详细的版本,请参阅
如果你想检查请求是否被路由到 ApiController
,你可以尝试 IExceptionFilter
来处理异常。
public class CustomExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (IsApi(context))
{
HttpStatusCode status = HttpStatusCode.InternalServerError;
var message = context.Result;
//You can enable logging error
context.ExceptionHandled = true;
HttpResponse response = context.HttpContext.Response;
response.StatusCode = (int)status;
response.ContentType = "application/json";
context.Result = new ObjectResult(new { ErrorMsg = message });
}
else
{
}
}
private bool IsApi(ExceptionContext context)
{
var controllerActionDesc = context.ActionDescriptor as ControllerActionDescriptor;
var attribute = controllerActionDesc
.ControllerTypeInfo
.CustomAttributes
.FirstOrDefault(c => c.AttributeType == typeof(ApiControllerAttribute));
return attribute == null ? false : true;
}
}
感谢其他人的所有建议,但经过更多的思考和想法后,我意识到我的方法一开始就不对——我应该在控制器中本地处理大多数异常并从那里回应。
我的错误处理中间件基本上与处理 MVC 未处理异常的方式相同。客户端将获得带有 HTML 响应的 500,但此时客户端无能为力,所以不会造成伤害。
感谢您的帮助!