簡體   English   中英

如何處理 ASP.NET Core 3 中 400 到 500 的異常

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM