ASP.NET Core中间件中渲染Razor视图
在中间件中执行完MVC的处理之后检查返回状态,如果是错误状态就直接渲染视图并输出
实现方式就是在Configure中注入ICompositeViewEngine实例,构造视图上下文,再渲染视图为字符串,最后输出。
第一种:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ICompositeViewEngine engine) { // 放到最后 app.Use(async (context, next) => { await next(); if (context.Response.StatusCode == (int)HttpStatusCode.NotFound) { context.Response.ContentType = "text/html"; var viewResult = engine.GetView("~/", "~/Views/Home/notfound.cshtml", true); if (!viewResult.Success) { await context.Response.WriteAsync("连错误视图都找不到了。。"); } using (var output = new StringWriter()) { var metadataProvider = new EmptyModelMetadataProvider(); var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); viewData["Name"] = "fan";//ViewData传参 //视图上下文对于视图渲染来说很重要,视图中的前后台交互都需要它 var viewContext = new ViewContext() { HttpContext = context, Writer = output, RouteData = new Microsoft.AspNetCore.Routing.RouteData() { //RouteData在这里传入视图,这样视图可以显示错误信息之类的数据 }, View = viewResult.View, ViewData = viewData, FormContext = new FormContext(), ActionDescriptor = new Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor() }; //渲染 await viewResult.View.RenderAsync(viewContext); //输出到响应体 await context.Response.WriteAsync(output.ToString()); } } }); }
第二种:
var actionDescriptor = context.GetEndpoint()?.Metadata.GetMetadata<ControllerActionDescriptor>() ?? new ControllerActionDescriptor(); var routeData = context.GetRouteData() ?? new RouteData(); var actionContext = new ActionContext(); actionContext.HttpContext = context; actionContext.RouteData = routeData; actionContext.ActionDescriptor = actionDescriptor; var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), actionContext.ModelState); viewData.Model = new ErrorViewModel { RequestId = Activity.Current?.Id ?? context.TraceIdentifier, Exception = innerException, StatusCode = statusCode }; string viewName = this._env.IsDevelopment() ? "Error" : "Home/Notfound"; var viewResult = new PartialViewResult() { ViewName = viewName,//部分视图名 ViewData = viewData }; context.Response.StatusCode = statusCode; await viewResult.ExecuteResultAsync(actionContext);
第三种:(未测试)
//var executor = context.RequestServices.GetRequiredService<IActionResultExecutor<PartialViewResult>>(); //await executor.ExecuteAsync(actionContext, viewResult);