How to extend an ASP.NET Core MVC project by Razor Pages?

Viewed 5037

I'm currently trying to extend an existing ASP.NET Core MVC project by a Razor page (since several tutorial videos claim that MVC, API, Razor and Blazor can coexist in the same project - but none of them shows how it's done).

I already figured out I need to extend Startup.cs by

services.AddRazorPages();

and

app.UseEndpoints(endpoints =>
{
    // This was here already
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    // I added this
    endpoints.MapRazorPages();
});

I tried simply adding a razor page "Test" to the Views folder, extending the _Layout.cshtml by

<li class="nav-item">
    <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Test">Test</a>
</li>

then extending HomeController by

    public IActionResult Test()
    {
        return View();
    }

However, this causes several issues with breakpoints not being hit, or the ViewData dictionary being null (with the identical code working in a pure Razor Page project), probably since it tries treating the Razor Page as an MVC view or something.

I've also tried adding something like

<li class="nav-item">
    <a class="nav-link text-dark" asp-area="" asp-page="/Home/Test">Test</a>
</li>

to the layout instead, but this produces an URL like

https://localhost:5001/?page=%2FHome%2FTest

when clicking the navbar item.

I can perfectly have both things in separate VS projects, but isn't there a way to use both of them in a single VS project and a single layout?

If you want to try it out before answering, use the following steps:

  1. Create a new project/solution in Visual Studio 2019
  2. Select "ASP.NET Core Web Application" as project template
  3. Click "Create" and select "Web Application (Model-View-Controller)" as template with default settings
  4. Add Razor Support in Startup.cs
  5. Try to make a simple razor page working in this project
2 Answers

The razor pages does not requires a controller.

The default directory is /Pages, then by default all pages should be inside Pages directory. If you want to change it you can do it by overriding the configuration in ConfigureServices on startup.

services.AddRazorPages(c=>c.RootDirectory = "/PagesRootDir");

To create a link to page, you should use asp-page tag. For example, if the page name is Test the physical path (by default) will be Pages\Test. To generate the link, you will need to use:

<a asp-page="/Test">Test Page</a>

By default the pages won't use the default layout, you can always override it.

@page
@model WebApplication1.Pages.TestModel
@{
    Layout = "_Layout";
}

<h1>
    Test Page
</h1>

To remove the layout:

Layout = null;

If you want to use the "Views\Shared\_Layout" on all the pages, you will need to create a _ViewStart with the following code:

@{
    Layout = "_Layout";
}

enter image description here

I've found a solution which seems to work for now: In Startup.cs, configure razor pages to look in the /Views folder instead of it's default /Pages (this obviously breaks convention):

services.AddRazorPages(configure => configure.RootDirectory = "/Views");

Using this, I can use the asp-page-style nav item without adapting the controller.

I will still accept anyone's answer if you can show me how to do this without breaking default conventions (My main issue is I have no idea how to make this work with a Pages folder, a Views folder and the _Layout.cshtml being in only one of them.)

Related