'how to return view from custom middleware?
My goal is intercept 404 status code using middleware and return custom view (interrupt execution).
I tried some examples. And, only await context.Response.WriteAsync("test 404 response error"); works. But this is not I need.
How to achieve this?
My next example does not work (I mean I got blank page or default Chrome not found page):
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);
}
}
}
Configuration:
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();
});
Controller and view:
[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>
Solution 1:[1]
To achieve a similar end, I created a helper method in my middleware class
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);
}
and then from the middleware where I actually wanted to return the view (after some conditional logic maybe, or doing some other things), I would
await GetViewResultTask(context, "~/Views/Home/NotRegistered.cshtml");
return;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | TZHX |
