0

I'm new to ASP.NET core, so I hope you bear with me on this one. This is similar to this unanswered question.

When I'm testing a brand new C# MVC project, and I enter a wrong URL, there's no info. Just a blank page.

To solve this, I have adapted startup.cs adding a UseStatusCodePagesWithReExecute() to return a static 404.html page. This works.

So far, so good.

Now, I am coding a basic login logic. For testing purposes, I'm calling return NotFound(); when the post parameters are missing. This doesn't return anything. I'm aware that 404 is not the correct response, but I have seen NotFound(); in the generated code and I think that's what's returning blank pages, so I want to solve that before moving on.

The app.UseDeveloperException(); doesn't seem to be called for this. I'm not sure how to test that.

Is there a way to override the NotFound(); behavior to get a 404.html somehow?

This is the Tutorial I have used to set up my project.

Edit: Based on the comments of Alexander Powolozki, I have replaced NotFound(); with Redirect("~/404.html");. This works.

// Wherever you want to return your standard 404 page
return Redirect("Home/StatusCode?code=404");


public class HomeController : Controller
{
    // This method allows for other status codes as well
    public IActionResult StatusCode(int? code)
    {
        // This method is invoked by Startup.cs >>> app.UseStatusCodePagesWithReExecute("/Home/StatusCode", "?code={0}");
        if (code.HasValue)
        {
            // here is the trick
            this.HttpContext.Response.StatusCode = code.Value;
        }

        //return a static file.
        try
        {
            return File("~/" + code + ".html", "text/html");
        }
        catch (FileNotFoundException)
        {
            return Redirect("Home/StatusCode?code=404");
        }
    }
}
GUI Junkie
  • 539
  • 1
  • 17
  • 31
  • AFAIK the first option with the 404.html is invoked when a request can't be processed because of missed routes to ressources like static content or controllers, in this case the preconfigured 404.html is returned. In the second case a routing was successfull and all the remaining processing is done by the logic e.g. the determined and invoked controller, so it's up to you to redirect to your created 404.html. – Alexander Powolozki May 28 '20 at 11:07
  • @AlexanderPowolozki The first case is solved. For the second case you're saying "don't use NotFound()", or do I have to create a NotFoundController class? – GUI Junkie May 28 '20 at 11:42
  • for the second case you have to redirect to your custom 404.html. – Alexander Powolozki May 28 '20 at 12:30
  • @AlexanderPowolozki Okay. This works. I don't see why NotFound() would not do that by default, but it works. If you make this into an answer I will accept it. – GUI Junkie May 28 '20 at 16:14
  • the reason becaus NotFound() does not do the job like you expect is because NotFound() returns the default NotFoundResult wich is the default 404 state and there is no rerouting to your custom 404.html. Request is rerouted to your custom 404.html page automatically only if someone requests a ressource, which can not be discovered. – Alexander Powolozki May 29 '20 at 07:20
  • i'm sorry, why did you unaccept my answer? – Alexander Powolozki Jun 04 '20 at 13:44
  • 1
    My answer is better for two reasons. 1. It reduces the number of round-trips. Instead of sending a 302 and then a 404 message, you only send the 404 message. 2. Your answer doesn't have code in it. I have attributed you in my question and in my answer. I hope you see now why I accepted my own answer. – GUI Junkie Jun 04 '20 at 14:17
  • when answering i always try to give topic starters a change to find the final result themselve by showing the way, not giving the last bit of code. Imho this way the learning effect is much deeper. – Alexander Powolozki Jun 04 '20 at 14:53
  • 1
    @AlexanderPowolozki Cheers. – GUI Junkie Jun 04 '20 at 15:05

2 Answers2

1

The first option with the 404.html is invoked when a request can't be processed because of missed routes to ressources like static content or controllers, in this case the preconfigured 404.html is returned. In the second case a routing was successfull and all the remaining processing is done by the logic e.g. the determined and invoked controller, so it's up to you to redirect to your created 404.html.

1

After working a little more on the question, I have found a way to do it without using Redirect as suggested by Alexander Powolozki.

I have created a Utilities class to return the 404 code and 404.html.

In the HomeController, I have the StatusCode IActionResult.

// This method is invoked by Startup.cs >>> app.UseStatusCodePagesWithReExecute("/Home/StatusCode", "?code={0}");
public IActionResult StatusCode(int? code)
{
    // Call the static method
    return Utilities.StatusCode(code: code.Value, this.HttpContext);
}

In Models, I've added a Utilities.cs.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using System.IO;

namespace MediaMgt.Models
{
    public static class Utilities
    {
        public static IActionResult StatusCode(int code, HttpContext httpContext)
        {
            // here is the trick
            httpContext.Response.StatusCode = code;

            //return a static file.
            try
            {
                return new VirtualFileResult("~/" + code + ".html", "text/html");
            }
            catch (FileNotFoundException)
            {
                httpContext.Response.StatusCode = 404;
                return new VirtualFileResult("~/404.html", "text/html");
            }
        }
    }
}

The reason to do it like this instead of using the Redirect method is to avoid a round-trip to the client with a 302. This method returns both the 404 error code and a standard 404.html.

You can easily add more functionality from here on.

GUI Junkie
  • 539
  • 1
  • 17
  • 31