ASP.NET Core 2.2 无法从自定义中间件调用 Razor 页面
ASP.NET Core 2.2 Can't invoke Razor Page from custom middleware
我正在尝试创建自定义异常处理中间件。类似于 -> app.UseExceptionHandler("/Error")。我将在中间件中记录错误,然后我想调用错误页面。
问题是,当我进行重定向时,context.Features.Get() 中的 IExceptionHandlerFeature 对象为 NULL。
似乎在执行 Razorpage 时清除了上下文异常。在原来的中间件中它以某种方式工作。
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Redirect("/ErrorHandling/Error");
await Task.CompletedTask;
}
}
这是我的 Razor 错误页面模型
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
private ILogger<ErrorModel> _logger;
public string RequestId { get; set; }
public string ExceptionPath { get; set; }
public string ExceptionMessage { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet(string executionPath)
{
var httpCtx = HttpContext;
var exceptionDetails = httpCtx.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionDetails != null)
{
_logger.LogError(httpCtx.Response.StatusCode, exceptionDetails.Error, exceptionDetails.Error.Message);
//Add data for view
ExceptionPath = exceptionDetails.Path;
ExceptionMessage = "An unexpected fault happened. Try again later.";
}
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
重定向后 httpCtx.Features.Get() 应该 return IExceptionHandlerPathFeature 对象,但它 returns NULL
从ExceptionHandlerMiddleware and ExceptionHandlerExtensions的源代码来看,你需要使用rewrite而不是redirect。
下面是自定义ExceptionMiddleware的简化代码
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory
)
{
_next = next;
_loggerFactory = loggerFactory;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
PathString originalPath = context.Request.Path;
context.Request.Path = "/Error";
try
{
var exceptionHandlerFeature = new ExceptionHandlerFeature()
{
Error = ex,
Path = originalPath.Value,
};
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await _next(context);
return;
}
catch (Exception ex2)
{
}
finally
{
context.Request.Path = originalPath;
}
}
}
我正在尝试创建自定义异常处理中间件。类似于 -> app.UseExceptionHandler("/Error")。我将在中间件中记录错误,然后我想调用错误页面。 问题是,当我进行重定向时,context.Features.Get() 中的 IExceptionHandlerFeature 对象为 NULL。 似乎在执行 Razorpage 时清除了上下文异常。在原来的中间件中它以某种方式工作。
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Redirect("/ErrorHandling/Error");
await Task.CompletedTask;
}
}
这是我的 Razor 错误页面模型
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
private ILogger<ErrorModel> _logger;
public string RequestId { get; set; }
public string ExceptionPath { get; set; }
public string ExceptionMessage { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet(string executionPath)
{
var httpCtx = HttpContext;
var exceptionDetails = httpCtx.Features.Get<IExceptionHandlerPathFeature>();
if (exceptionDetails != null)
{
_logger.LogError(httpCtx.Response.StatusCode, exceptionDetails.Error, exceptionDetails.Error.Message);
//Add data for view
ExceptionPath = exceptionDetails.Path;
ExceptionMessage = "An unexpected fault happened. Try again later.";
}
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
重定向后 httpCtx.Features.Get() 应该 return IExceptionHandlerPathFeature 对象,但它 returns NULL
从ExceptionHandlerMiddleware and ExceptionHandlerExtensions的源代码来看,你需要使用rewrite而不是redirect。
下面是自定义ExceptionMiddleware的简化代码
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggerFactory _loggerFactory;
public ExceptionMiddleware(
RequestDelegate next,
ILoggerFactory loggerFactory
)
{
_next = next;
_loggerFactory = loggerFactory;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
var logger = _loggerFactory.CreateLogger("Serilog Global exception logger");
logger.LogError($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
PathString originalPath = context.Request.Path;
context.Request.Path = "/Error";
try
{
var exceptionHandlerFeature = new ExceptionHandlerFeature()
{
Error = ex,
Path = originalPath.Value,
};
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await _next(context);
return;
}
catch (Exception ex2)
{
}
finally
{
context.Request.Path = originalPath;
}
}
}