【问题标题】:how to return view from custom middleware?如何从自定义中间件返回视图?
【发布时间】:2022-08-16 18:10:00
【问题描述】:

我的目标是使用中间件拦截 404 状态代码并返回自定义视图(中断执行)。

我尝试了一些例子。而且,只有await context.Response.WriteAsync(\"test 404 response error\"); 有效。但这不是我需要的。

如何做到这一点?

我的下一个示例不起作用(我的意思是我得到了空白页面或默认的 Chrome 未找到页面):

public class CustomError404Middleware
{
    private readonly RequestDelegate _next;

    public CustomError404Middleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next(context);

        if (context.Response.StatusCode == 404 && !context.Response.HasStarted)
        {
            //Re-execute the request so the user gets the error page
            var originalPath = context.Request.Path.Value;
            context.Items[nameof(Defaults.ORIGINAL_PATH)] = originalPath;
            context.Request.Path = \"Error/404\";
            // context.Request.Path = \"/Error/404\";

            await _next(context);
        }
    }
}

配置:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseMigrationsEndPoint();
            }
            else
            {
                app.UseExceptionHandler(\"/Home/Error\");
                // 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.UseStatusCodePages();

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseMiddleware<RequestLoggerMiddleware>();
            app.UseMiddleware<CustomError404Middleware>();

.............. skipped (Rollbar, CORS) ..............

            app.UseSession();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: \"dashboard\",
                    pattern: \"{controller=Home}/{action=Index}\");
                endpoints.MapRazorPages();
                endpoints.MapMetrics();
            });

控制器和视图:

    [AllowAnonymous]
    public class ErrorController : Controller
    {
        [ActionName(\"404\")]
        public IActionResult PageNotFound()
        {
            ViewData[nameof(Defaults.ORIGINAL_PATH)] = \"unknown\";

            if (HttpContext.Items.ContainsKey(nameof(Defaults.ORIGINAL_PATH)))
            {
                ViewData[nameof(Defaults.ORIGINAL_PATH)] = HttpContext.Items[Defaults.ORIGINAL_PATH] as string;
            }

            return View();
        }
    }
@ViewData[nameof(Defaults.ORIGINAL_PATH)]

<div>
    <p>
        test
    </p>
</div>

    标签: middleware .net-5 404-page


    【解决方案1】:

    为了达到类似的目的,我在中间件类中创建了一个辅助方法

    private Task GetViewResultTask(HttpContext context, string viewName)
    {
        var viewResult = new ViewResult()
        {
            ViewName = viewName
        };
    
        var executor = context.RequestServices.GetRequiredService<IActionResultExecutor<ViewResult>>();
        var routeData = context.GetRouteData() ?? new Microsoft.AspNetCore.Routing.RouteData();
        var actionContext = new ActionContext(context, routeData,
        new Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor());
        return executor.ExecuteAsync(actionContext, viewResult);
    }
    

    然后从我真正想要返回视图的中间件(可能在一些条件逻辑之后,或者做一些其他事情之后),我会

    await GetViewResultTask(context, "~/Views/Home/NotRegistered.cshtml");
    return;
    

    【讨论】:

    • 你好。这是某种死灵张贴:) 但照原样......我无法通过您提供的解决方案取得成功。解决方案有问题,或者我没有足够的经验。所以,我用“重新执行”做到了谢谢。
    【解决方案2】:

    最后,经过所有尝试,我使用内置的“重新执行”解决了问题

    //startup.cs
    app.UseStatusCodePagesWithReExecute("/Error/{0}");
    

    控制器和视图:

    //controller
    [HttpGet]
    [ActionName("404")]
    public async Task<IActionResult> Error404()
    {
        return await Task.Run(() => View(ErrorModel(HttpContext)));
    }
    
    private ErrorViewModel ErrorModel(HttpContext context)
    {
        return new ErrorViewModel(OriginalUrl(context), RequestId(context));
    }
    
    private string OriginalUrl(HttpContext context)
    {
        var feature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
    
        return feature?.OriginalPath;
    }
    
    private string RequestId(HttpContext context)
    {
       return Activity.Current?.Id ?? context.TraceIdentifier;
    }
    
    //view just as a sample
    <div class="h-100 mt-4">
        <div class="d-flex justify-content-center align-items-center h-100">
            <div class="text-center">
                <p class="font-weight-bold" style="font-size:10rem">404</p>
                <br />
                <p class="font-weight-bold" style="font-size:3rem">Requested page not found</p>
                <br />
                <p class="font-weight-bold">ID: @Model.RequestId</p>
                <p class="font-weight-bold">URL: @Model.OriginalUrl</p>
            </div>
         </div>
     </div>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-28
      • 2021-12-04
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多