我正在尝试在使用 .Net 6 构建的网站上实现自定义错误页面,并尝试使用以下代码实现:
程序.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseExceptionHandler("/Shared/Error");
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
共享控制器.cs
public class SharedController : BaseController
{
private readonly string _cookieKey = "session-info";
private readonly ILogger<SharedController> _logger;
public SharedController(ILogger<SharedController> logger, IConfiguration configuration) : base(configuration)
{
_logger = logger;
}
public IActionResult Error()
{
return View(new ErrorViewModel());
}
}
BaseController.cs
public class BaseController : Controller
{
private readonly string _cookieKey = "session-info";
public IConfiguration _config;
public BaseController(IConfiguration configuration)
{
_config = configuration;
}
public async Task CheckLogin(BaseModel? model)
{
if(model == null)
{
return;
}
model.UserName = "";
model.UserId = -1;
model.IsAdmin = false;
model.LoggedIn = false;
var baseAddress = new Uri(_config["Config:BaseAddress"]);
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
{
var siteCookies = HttpContext.Request.Cookies.Where(cookie => cookie.Key == _cookieKey); ;
if (!siteCookies.Any())
{
return;
}
var siteCookie = siteCookies.First();
cookieContainer.Add(baseAddress, new Cookie(siteCookie.Key, siteCookie.Value));
var client = new HttpClient(handler);
var response = await client.GetAsync(baseAddress.AbsoluteUri + "api/authenticate");
if (response != null && response.IsSuccessStatusCode)
{
var userObj = await response.Content.ReadFromJsonAsync<UserLookup>();
if (userObj.Key != null && userObj.Key != "")
{
model.UserName = userObj.Key;
model.UserId = userObj.Id;
model.LoggedIn = true;
}
}
response = await client.GetAsync(baseAddress.AbsoluteUri + "api/isAdmin");
if (response != null && response.IsSuccessStatusCode)
{
model.IsAdmin = await response.Content.ReadFromJsonAsync<bool>();
}
}
}
private class Login
{
public string UserName { get; set; }
public string Password { get; set; }
}
private class UserLookup
{
public string Key { get; set; }
public int Id { get; set; }
}
}
错误.cshtml
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
Layout = "_Layout";
}
@if (true)
{
<h1>Error.</h1>
<h2>An error occurred while processing your request.</h2>
}
请注意,我将设置移到 IsDevelopment 块之外只是为了测试。 不过,无论是在开发配置还是发布配置上进行测试,我都会得到相同的结果。 当我遇到异常时,它会被中间件捕获,错误控制器方法运行,我什至可以通过断点看到视图正在运行。 但是,我只是在浏览器中看到一个完全空白的页面。另外,检查网络选项卡时,我仍然看到返回 500 错误。 我还应该注意,我只能通过抛出异常来触发此操作。如果我转到一个不存在的页面并收到 404,我只会得到一个空白页面,而不会命中任何处理程序。
由于流程通过 Error 方法和 cshtml 代码移动,我认为一切都连接正常,但我得到一个完全空白的页面。甚至布局都没有加载。在搜索中,我没有看到这个特定的问题弹出,所以除了将我的配置更改为发布之外,我没有尝试任何其他方法。
我在关闭“仅我的代码”进行调试时发现了这一点。 我的 ErrorViewModel 类继承了 PageModel。 在中间件的某个时刻,它期望它是 BaseModel 类型。由于类型不匹配,它正在考虑未处理的异常并调用 Rethrow,这会重新抛出错误,导致我看到 500 和空白页。 我不确定为什么这是预期的所有来龙去脉,但确实如此。
长话短说,我将 ErrorViewModel 更改为继承 BaseModel 而不是 PageModel,现在我按预期获得了自定义错误页面。