PROWAREtech








ASP.NET Core: Handle "View Was Not Found" Server Error
View not found errors are easy to handle.
There are examples using .NET 6 and .NET Core 3.1. If using .NET 5 then follow the .NET Core 3.1 code.
First, create a new ASP.NET Core Web Application Project or open an existing one.
Modify the C# file named Program.cs. Add app.UseStatusCodePagesWithReExecute("/Home/Error/{0}")
as in the following code snippet. This single line of code is key to making this error handling function properly.
if (app.Environment.IsDevelopment())
app.UseDeveloperExceptionPage();
else
{
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}"); // NOTE: ADD THIS LINE OF CODE TO THE PROGRAM.CS FILE
app.UseExceptionHandler("/Home/Error");
}
Modify ErrorViewModel.cs as follows. Most of this code file is modified.
using System;
namespace ProjectName.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public string Path { get; }
public int StatusCode { get; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public ErrorViewModel(string path = null)
{
StatusCode = 500;
Path = path;
}
public ErrorViewModel(int statusCode, string path = null)
{
StatusCode = statusCode;
Path = path;
}
}
}
Modify the HomeController
(located in the HomeController.cs file). The modifications are all noted.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ProjectName.Models;
namespace ProjectName.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index(string id) // NOTE: THIS LINE MODIFIED FOR TESTING
{
return View(viewName: id); // NOTE: THIS LINE MODIFIED FOR TESTING
}
public IActionResult Privacy()
{
return View();
}
// NOTE: THE FOLLOWING 15 LINES OF CODE ARE ADDED/MODIFIED
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] // NOTE: MUST NOT ALLOW CACHING
public IActionResult Error()
{
var ehpf = HttpContext.Features.Get<Microsoft.AspNetCore.Diagnostics.IExceptionHandlerPathFeature>();
if (ehpf.Error.Source == "Microsoft.AspNetCore.Mvc.ViewFeatures" && (ehpf.Error.HResult == -2146233079 || ehpf.Error.Message.Contains("was not found")))
return View(new ErrorViewModel(404, ehpf.Path));
return View(new ErrorViewModel(ehpf.Path) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[Route("Home/Error/{id}")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] // NOTE: MUST NOT ALLOW CACHING
public IActionResult Error(int id)
{
return View(new ErrorViewModel(id));
}
}
}
Modify Error.cshtml as follows.
@model ErrorViewModel
@{
Context.Response.StatusCode = Model.StatusCode;
switch (Context.Response.StatusCode)
{
case 404:
ViewData["Title"] = "404: Resource Not Found";
break;
default: // NOTE: CAN HANDLE OTHER STATUS CODES
ViewData["Title"] = Context.Response.StatusCode + ": Error";
break;
}
}
<h2>@ViewData["Title"]</h2>
@if (Model.ShowRequestId)
{
<p><strong>Request ID:</strong> <code>@Model.RequestId</code></p>
}
<pre>@Model.Path</pre>
Modify launchSettings.json to use Production settings. Only two lines of code need to be modified here, from "Development" to "Production".
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56789",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
},
"ProjectName": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
}
Modify Index.cshtml as follows.
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4"><a href="/Home/Index/BogusView">Open "BogusView"</a></h1>
</div>
Now, run the project and try to load a view that does not exist, such as "BogusView" which a link is provided for on the home page. A 404 resource not found error should be shown instead of a 500 internal server error.
Modify the C# file named Startup.cs. Add app.UseStatusCodePagesWithReExecute("/Home/Error/{0}")
as in the following code. This single line of code is key to making this error handling function properly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ProjectName
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}"); // NOTE: THIS LINE IS NEW
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Modify ErrorViewModel.cs as follows. Most of this code file is modified.
using System;
namespace ProjectName.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }
public string Path { get; }
public int StatusCode { get; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public ErrorViewModel(string path = null)
{
StatusCode = 500;
Path = path;
}
public ErrorViewModel(int statusCode, string path = null)
{
StatusCode = statusCode;
Path = path;
}
}
}
Modify the HomeController
(located in the HomeController.cs file). The modifications are all noted.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ProjectName.Models;
namespace ProjectName.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index(string id) // NOTE: THIS LINE MODIFIED FOR TESTING
{
return View(viewName: id); // NOTE: THIS LINE MODIFIED FOR TESTING
}
public IActionResult Privacy()
{
return View();
}
// NOTE: THE FOLLOWING 15 LINES OF CODE ARE ADDED/MODIFIED
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] // NOTE: MUST NOT ALLOW CACHING
public IActionResult Error()
{
var ehpf = HttpContext.Features.Get<Microsoft.AspNetCore.Diagnostics.IExceptionHandlerPathFeature>();
if (ehpf.Error.Source == "Microsoft.AspNetCore.Mvc.ViewFeatures" && (ehpf.Error.HResult == -2146233079 || ehpf.Error.Message.Contains("was not found")))
return View(new ErrorViewModel(404, ehpf.Path));
return View(new ErrorViewModel(ehpf.Path) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[Route("Home/Error/{id}")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] // NOTE: MUST NOT ALLOW CACHING
public IActionResult Error(int id)
{
return View(new ErrorViewModel(id));
}
}
}
Modify Error.cshtml as follows.
@model ErrorViewModel
@{
Context.Response.StatusCode = Model.StatusCode;
switch (Context.Response.StatusCode)
{
case 404:
ViewData["Title"] = "404: Resource Not Found";
break;
default: // NOTE: CAN HANDLE OTHER STATUS CODES
ViewData["Title"] = Context.Response.StatusCode + ": Error";
break;
}
}
<h2>@ViewData["Title"]</h2>
@if (Model.ShowRequestId)
{
<p><strong>Request ID:</strong> <code>@Model.RequestId</code></p>
}
<pre>@Model.Path</pre>
Modify launchSettings.json to use Production settings. Only two lines of code need to be modified here, from "Development" to "Production".
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:56789",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
},
"ProjectName": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
}
}
}
}
Modify Index.cshtml as follows.
@{
ViewData["Title"] = "Home Page";
}
<div class="text-center">
<h1 class="display-4"><a href="/Home/Index/BogusView">Open "BogusView"</a></h1>
</div>
Now, run the project and try to load a view that does not exist, such as "BogusView" which a link is provided for on the home page. A 404 resource not found error should be shown instead of a 500 internal server error.