Mos*_*afa 2 c# asp.net-core-mvc asp.net-core
我有一个 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?}");
});
}
}
Run Code Online (Sandbox Code Playgroud)
我做了一个错误控制器,如下所示:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?任何帮助都会得到帮助!
考虑通过将错误处理逻辑移动到专用的“中间件”类来简化您的控制器。
想象一个像这样的简单控制器,它所做的只是定义路由的目标页面,并包含一个示例异常来模拟 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");
}
}
Run Code Online (Sandbox Code Playgroud)
在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" });
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
Startup.cs也需要一个引用,using TestError.Infrastructure;因为中间件类被创建为Infrastructure\ErrorHandler.cs
中间件类查看 HttpContext 管道context.Response.StatusCode并使用 switch 语句,根据需要调用自定义方法来响应每个错误,并且我为 404 错误添加了一个子句。
您可以根据需要为不同的错误代码添加更多子句,并附加自定义方法来处理特定情况,或者如果您想确保错误处理程序不会变得过于复杂和具体,则将它们构建在单独的类中。
一般代码异常作为 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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
该HandleException方法创建一个重定向到“/错误”页面。
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>
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
示例用法,有一个主页如下(有一个布局页面)
@{
ViewData["Title"] = "Home";
Layout = "~/Views/Shared/_Layout_Main.cshtml";
}
<h1>Hello World</h1>
Run Code Online (Sandbox Code Playgroud)
示例 1,/Home/Home:查找Home.cshtml
示例 2,/Nopage:重定向到PageNotFound.cshtml
示例 3,
/Home/Bogus:抛出异常并重定向到Error.cshtml

希望这有助于错误处理。对此有很多变化,如上所述,您可以添加更多 switch 子句,甚至包括 500 的特定案例。
更详细的示例还包括一些日志记录,为了简单起见,我将其排除在外。
| 归档时间: |
|
| 查看次数: |
5053 次 |
| 最近记录: |