12

On a ASP.NET Core Razor Page we can do this to change the default folder-based route:

@page "/xxx/yyy"

but trying to do this with a strongly typed property in some class Constants.Routes does not work

public const string Myroute = "/mysuperroute"; 

and

@page @Constants.Routes.Myroute

I am getting an error at compile time The 'page' directive expects a string surrounded by double quotes.

Is there a way around this? I would like to avoid route duplication through the options e.g. https://learn.microsoft.com/en-us/aspnet/core/razor-pages/razor-pages-conventions?view=aspnetcore-2.2#configure-a-page-route Thanks

Octopus
  • 661
  • 4
  • 21

4 Answers4

10

Little late to the party, but I had the same issue and found the RouteAttribute which associates the component with a given route template.

So you can do the following in your razor component and have it available under {host}:{port}/test:

@attribute [Microsoft.AspNetCore.Components.RouteAttribute(Href)]


@code {
  public const string Href = "test";
}

In a NavLink you can now do this:

<NavLink class="nav-link" href="@TestComponent.Href">
    Test Entry
</NavLink>

Source

Radall
  • 394
  • 4
  • 17
  • Just so it's clear for future searchers -- with the `@attribute` there's no need for `@page`. You can also have the constant in your page model (and you might have to add a `@using`). And because attribute is already code, you don't need an `@` in front of your constant variable. – Slate May 28 '21 at 10:34
  • I apologize for so many comments and deletes: So - this solution works on .razor pages and files, whereas the solution posted bellow works for cshtml files/pages. This is the only way I found that they both work. Thank you for this! – That Marc Jul 04 '21 at 14:23
3

I don't know if a .NET core 3.1 thing, but RouteAttribute didn't work for RazorPages.

@page
@attribute [Microsoft.AspNetCore.Razor.Hosting.RazorCompiledItemMetadata("RouteTemplate", MyRoutes.QualificationQueue)]
BillRob
  • 4,659
  • 4
  • 26
  • 38
1

If you don't like referencing the component/pages directly you can adapt @Radall's excellent answer as

@attribute [Route(StaticRoutes.Dashboard)]

public static class StaticRoutes
{
    public const string Dashboard = "/app/dashboard";

    public static class MyArea
    {
        public const string Home = "/app/my-area";
        public const string Second = "/app/my-area/second";
    }
}

And use it:

<NavLink class="nav-link" href="@StaticRoutes.Dashboard">
    Dashboard
</NavLink>
<NavLink class="nav-link" href="@StaticRoutes.MyArea.Home">
    Area
</NavLink>
Eonasdan
  • 7,563
  • 8
  • 55
  • 82
0

I could not find a way to specify a page route in a strongly typed manner for the razor pages in .Net Core 6.0.

  1. The @page directive expects a string and would throw an exception for a variable.

  2. The RouteAttribute is simply ignored

  3. There is a way of adding extra routes in Program.cs like this:

    builder.Services.AddRazorPages().AddRazorPagesOptions(options => { options.Conventions.AddPageRoute("/Index", "default.aspx"); });

But it is still required for you to provide the page name as a parameter.

There is however a way of mapping a PageModel class to the corresponding page name.

You need to implement IPageApplicationModelConvention and add it to the service container:

public class InitStructurePageRouteModelConvention : IPageApplicationModelConvention
    {
        public void Apply(PageApplicationModel model)
        {
            var page = Structure.FindByTypeInfo(model.ModelType);

            if (page != null)
            {
                page.PagePath = model.ViewEnginePath;
                page.Area = model.AreaName;
            }
        }
    }

The PageApplicationModel has everything we need to do the mapping between PageModel and PagePath. The "Structure" is a tree like object holding various metadata (including PageModel type, PagePath and Area) about application pages.

The registration in service container:

builder.Services.AddRazorPages(options =>
{
    options.Conventions.Add(new InitStructurePageRouteModelConvention());
})

The "Apply" method will be called for every razor page.

So instead of setting the page routes according to the application structure you can have the structure populated with the PageModels and map the Page names during the Apply call of IPageApplicationModelConvention.

Kind of reverse approach: Not setting the routes according to your structure but updating your structure with existing routes (or page names).

The downside is that you cannot have multiple pages for one PageModel class.

But you can now use the page.PagePath from the Structure object in the routing generation.

Sorry for not providing more details about the Structure object but it would make the post too big while being unrelated to your needs.

dazipe
  • 11
  • 3