[英]How handle exceptions from 400 to 500 in ASP.NET Core 3
我有一個 ASP.NET Core MVC 項目(Core 的版本是 3),我必須處理至少兩個異常,例如 404 和 500,並且有一個 404 的視圖應該說“抱歉,找不到該頁面”和另一個頁面對於錯誤 500,應該說“處理您的請求時發生錯誤”。 這些頁面必須具有 DefaultLayout。 我的 Startup.cs 如下:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDistributedMemoryCache();
services.AddSession();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddScoped<Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration>();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error/500");
// 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.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 404 && !ctx.Response.HasStarted)
{
//Re-execute the request so the user gets the error page
string originalPath = ctx.Request.Path.Value;
ctx.Items["originalPath"] = originalPath;
ctx.Request.Path = "/error/404";
await next();
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
我制作了一個錯誤控制器,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace AgentRegister.Controllers
{
[Route("error")]
public class ErrorController : Controller
{
private readonly TelemetryClient _telemetryClient;
public ErrorController(TelemetryClient telemetryClient)
{
_telemetryClient = telemetryClient;
}
[Route("500")]
public IActionResult AppError()
{
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
_telemetryClient.TrackException(exceptionHandlerPathFeature.Error);
_telemetryClient.TrackEvent("Error.ServerError", new Dictionary<string, string>
{
["originalPath"] = exceptionHandlerPathFeature.Path,
["error"] = exceptionHandlerPathFeature.Error.Message
});
return View();
}
[Route("404")]
public IActionResult PageNotFound()
{
string originalPath = "unknown";
if (HttpContext.Items.ContainsKey("originalPath"))
{
originalPath = HttpContext.Items["originalPath"] as string;
}
_telemetryClient.TrackEvent("Error.PageNotFound", new Dictionary<string, string>
{
["originalPath"] = originalPath
});
return View();
}
}
}
我怎樣才能做到這一點? 任何幫助將不勝感激!
考慮通過將錯誤處理邏輯移動到專用的“中間件”class 來簡化您的 controller。
想象一下像這樣一個簡單的 controller,它所做的只是定義路由的目標頁面,並包含一個示例異常來模擬 500 錯誤。 它不關心特定的錯誤類型。 (為簡單起見,允許匿名訪問。)
該項目稱為TestError 。
using System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace TestError.Controllers
{
[AllowAnonymous]
public class HomeController : Controller
{
public HomeController() { }
[HttpGet]
public ViewResult Home() => View("Home");
[HttpGet]
public ViewResult Bogus() => throw new Exception("Bogus error");
[HttpGet]
public ViewResult Error() => View("Error");
[HttpGet]
public ViewResult PageNotFound() => View("PageNotFound");
}
}
在Startup.cs中,就在路由定義的上方,有一個對錯誤處理程序的引用,即app.UseMiddleware<ErrorHandler>();
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using TestError.Infrastructure;
namespace TestError
{
public class Startup
{
// Updated this class for ASP.NET Core 3
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseMiddleware<ErrorHandler>();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "Default",
pattern: "{controller=Home}/{action=Home}/{id?}");
endpoints.MapControllerRoute(name: "Error",
"error",
new { controller = "Home", action = "Error" });
endpoints.MapControllerRoute(name: "PageNotFound",
"pagenotfound",
new { controller = "Home", action = "PageNotFound" });
});
}
}
}
Startup.cs也需要一個參考作為using TestError.Infrastructure;
作為中間件 class 創建為Infrastructure\ErrorHandler.cs
中間件 class 查看 HttpContext 管道context.Response.StatusCode
並使用 switch 語句,根據需要調用自定義方法來響應每個錯誤,並且我添加了 404 錯誤的子句。
您可以根據需要為不同的錯誤代碼添加更多子句,以及用於處理特定情況的 append 自定義方法,或者如果您想確保錯誤處理程序不會變得過於復雜和具體,則可以將它們構建在單獨的類中。
一般代碼異常作為 500 個錯誤單獨處理,由 catch 塊捕獲。
using System;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace TestError.Infrastructure
{
public class ErrorHandler
{
private readonly RequestDelegate _next;
public ErrorHandler(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
// Handle specific HTTP status codes
switch (context.Response.StatusCode)
{
case 404:
HandlePageNotFound(context);
break;
case 418:
// Not implemented
break;
default:
break;
}
}
catch (Exception e)
{
// Handle uncaught global exceptions (treat as 500 error)
HandleException(context, e);
}
finally
{
}
}
// 500
private static void HandleException(HttpContext context, Exception e)
{
context.Response.Redirect("/Error");
}
// 404
private static void HandlePageNotFound(HttpContext context)
{
// Display an information page that displays the bad url using a cookie
string pageNotFound = context.Request.Path.ToString().TrimStart('/');
CookieOptions cookieOptions = new CookieOptions();
cookieOptions.Expires = DateTime.Now.AddMilliseconds(10000);
cookieOptions.IsEssential = true;
context.Response.Cookies.Append("PageNotFound", pageNotFound, cookieOptions);
context.Response.Redirect("/PageNotFound");
}
}
}
HandleException方法創建到“/Error”頁面的重定向。
Error.cshtml和你期望的差不多
@{
Layout = "~/Views/Shared/_Layout_Main.cshtml";
ViewData["Title"] = "Error";
}
<div id="dataSection">
<div class="TextLine Label">An error occurred while processing your request</div>
</div>
HandlePageNotFound創建一個短暫的 cookie 來存儲請求頁面的地址,並重定向到“/PageNotFound”。
PageNotFound.cshtml引用 cookie 以顯示有意義的錯誤
@{
Layout = "_Layout_Main";
ViewData["Title"] = "Page Not Found";
string notFoundMessage = "Sorry, The page cannot be found";
string pageNotFound = Context.Request.Cookies["PageNotFound"];
if (pageNotFound != null){
notFoundMessage += " : ";
}
}
<div id="dataSection">
<div class="TextLine Label">@notFoundMessage<b>@pageNotFound</b></div>
</div>
示例用法,有一個主頁如下(帶布局頁面)
@{
ViewData["Title"] = "Home";
Layout = "~/Views/Shared/_Layout_Main.cshtml";
}
<h1>Hello World</h1>
示例 1, /Home/Home :查找Home.cshtml 示例 2, /Nopage :重定向到PageNotFound.cshtml 示例 3, /Home/Bogus :拋出異常並重定向到Error.cshtml
希望這有助於錯誤處理。 這有很多變化,如前所述,您可以添加更多 switch 子句,甚至包括 500 的特定情況。
更詳細的示例還包括一些日志記錄,為簡單起見,我已將其排除在外。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.