ASP.NET MVC 5 > AccountController > Login > HTTP 404

Viewed 53

I'm using Adam Freeman's book called "Pro ASP.NET MVC", and trying to implement the chapter 12, a simple web application of Authentication.

This web application uses:

  1. Login.cshtml (~/Account/Login);
  2. AccountController.cs
  3. Web.config

You can see Login.cshtml here:

@model SportsStore.WebUI.Models.LoginViewModel

@{
    /*
    chapter 12 - SportsStore: Security & Finishing Touches
        Securing the Administration Controller
            Creating the View 312
                Listing 12-9. The Contents of the Login.cshtml File
   */

    ViewBag.Title = "Admin: Log In";
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}

<div class="panel">
    <div class="panel-heading">
        <h3> Log In</h3>
    </div>
    <div class="panel-body">
        <p class="lead">Please log in to access the administration area:</p>
        @using (Html.BeginForm())
        {
            @Html.ValidationSummary()
            <div class="form-group">
                <label>User Name:</label>
                @Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
            </div>
            <div class="form-group">
                <label>Password:</label>
                @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
            </div>
            <input type="submit" value="Log in" class="btn btn-primary" />
        }
    </div>
</div>

This is the AccountController class:

using System.Web.Mvc;
using SportsStore.WebUI.Infrastructure.Abstract;
using SportsStore.WebUI.Models;

namespace SportsStore.WebUI.Controllers
{
    /*
    chapter 12 - SportsStore: Security & Finishing Touches
        Securing the Administration Controller
            Creating the Account Controller 312
                Listing 12-8. The Contents of the AccountController.cs File
     */
    public class AccountController : Controller
    {
        IAuthProvider authProvider;

        public AccountController(IAuthProvider auth)
        {
            authProvider = auth;
        }

        [HttpPost]
        public ActionResult Login(LoginViewModel model, string returnUrl)
        {
            if (authProvider.Authenticate(model.UserName, model.Password))
            {
                return Redirect(returnUrl ?? Url.Action("Index", "Admin"));
            }
            else
            {
                return View();
            }
        }
    }
}

And here's the web.config file:

<system.web>
    <compilation debug="true" targetFramework="4.7.2" />
    <httpRuntime targetFramework="4.7.2" />

    <!--
    chapter 12 - SportsStore: Security & Finishing Touches
        Securing the Administration Controller
            Creating a Basic Security Policy
                Listing 12-1. Configuring Forms Authentication in the Web.config File
                Listing 12-2. Defining a Username and Password in the Web.config File                   
    -->

    <authentication mode="Forms">
        <forms loginUrl="~/Account/Login" timeout="2880">
            <credentials passwordFormat="Clear">
                <user name="admin" password="secret" />
            </credentials>
        </forms>
    </authentication>
</system.web>

Maybe my mistake is here? RouteConfig/RegisterRoutes:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
    null,
        "",
        new { controller = "Product", action = "List", category = (string)null, page = 1 }
    );

routes.MapRoute(
    null,
    "Page{page}",
    new { controller = "Product", action = "List", category = (string)null },
    new { page = @"\d+" }
);

routes.MapRoute(
    null,
    "{category}",
    new { controller = "Product", action = "List", page = 1 }
);

routes.MapRoute(
    null,
    "{category}/Page{page}",
    new { controller = "Product", action = "List" },
    new { page = @"\d+" }
);

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

When I run the web application I get this HTTP 404 message

Server error in application '/'

The resource cannot be found.
Request URL: Account/Login

What's my mistake?

3 Answers

You have a Login method on the AccountController that takes an HttpPost but in order to get the view you also need an HttpGet endpoint:

[HttpGet]
public ActionResult Login(string returnUrl)
{
    return View();
}

With the appropriate Login.cshtml to show the login form of course.

Also make sure you have the following added to your RouteConfig

routes.MapMvcAttributeRoutes();

Your AccountController has only one method (Login) and it has the HttpPost attribute. I'm assuming based on what your describing you're tying to hit the endpoint in your web browser by just going to /Account/Login. The reason you get a 404 is you don't have a Login method in that uses with an HttpGet attribute.

If you create something like:

[HttpGet]
public ActionResult Login()
{
    return Content("Hi there!");
}

You would get "Hi there" back when you try to hit the endpoint in the browser just to test and see if you can hit the endpoint at all.

I would recommend looking at the MS Docs on MVC Views and how to use them to help your situation - https://docs.microsoft.com/en-us/aspnet/core/mvc/views/overview?view=aspnetcore-6.0

Thanks guys,

The problem was solved because your help, I will show you the modification in the code:

using System.Web.Mvc;
using SportsStore.WebUI.Infrastructure.Abstract;
using SportsStore.WebUI.Models;

namespace SportsStore.WebUI.Controllers
{
    /*
    chapter 12 - SportsStore: Security & Finishing Touches
        Securing the Administration Controller
            Creating the Account Controller 312
                Listing 12-8. The Contents of the AccountController.cs File
     */
    public class AccountController : Controller
    {
        IAuthProvider authProvider;

        public AccountController(IAuthProvider auth)
        {
            authProvider = auth;
        }

        [HttpPost]
        public ActionResult Login(LoginViewModel model, string returnUrl)
        {
            if (authProvider.Authenticate(model.UserName, model.Password))
            {
                return Redirect(returnUrl ?? Url.Action("Index", "Admin"));
            }
            else
            {
                return View();
            }
        }

        [HttpGet]
        public ActionResult Login()
        {
            return View();
        }
    }
}
Related