Search code examples
asp.net-corerazor-pages

Routing subfolder to root URLs


In a Razor Pages project I have to override the default UI for ASP.NET Identity. Other that the specific page requirements, I don't want URLs like /Identity/Account/Whatever - my pages will be /login, /logout, etc.

However I still would like to group the authentication pages in a subfolder (not to pollute the top folder), but serve them from "root" URLs.

...
Pages
  /Auth
    Login.cshtml           -> /login
    Logout.cshtml          -> /logout
    ResetPassword.cshtml   -> /resetpassword
    ...
  Index.cshtml
  Privacy.cshtml
...

Currently to achieve this I have the following code in my Startup.cs

services.AddRazorPages(options =>
{
  options.Conventions.AddPageRoute("/Auth/Login", "login");
  options.Conventions.AddPageRoute("/Auth/Logout", "logout");
  options.Conventions.AddPageRoute("/Auth/ResetPassword", "resetpassword");
  ...
});

Can this be achieved with some folder convention? Also I don't want to have `/auth/{page}` URLs still working (which is a problem with the current approach).

Solution

  • You can achieve this with a custom Page route action convention.

    You can change your code like below.

     services.AddRazorPages(options =>
                    {
                        options.Conventions.AddPageRoute("/Auth/Login", "login");
                        options.Conventions.AddPageRoute("/Auth/Logout", "logout");
                        options.Conventions.AddPageRoute("/Auth/ResetPassword", "resetpassword");
                        options.Conventions.AddFolderRouteModelConvention("/", model =>
                        {
                            var selectorCount = model.Selectors.Count;
                            for (var i = selectorCount - 1; i >= 0; i--)
                            {
                                var selectorTemplate = model.Selectors[i].AttributeRouteModel.Template;
    
                                if (selectorTemplate.StartsWith("Auth")) 
                                    model.Selectors.RemoveAt(i);
                            }
                        });
                    });