ASP.NET Core Gotchas – No. 3 Why don't my hyperlinks work on my Razor Pages in ASP.NET Core 2.0?

Recently I decided to take Razor Pages, a new feature in ASP.NET Core 2.0, out for a spin. I’ll be blogging about that experience and how I migrated some basic views of an existing application over to Razor Pages in a future post.

In this blog post I wanted to concentrate on a simple gotcha which left me confused for a little while. You are only likely to hit this issue if you are starting with an existing MVC based web application and migrating some or all of your Views over to Razor Pages or starting with an Empty web application template. New Razor Pages based projects using the “Web Application” template will be setup correctly by default.

The symptoms I experienced were that after moving some of my Views and making them Razor Pages, the hyperlinks were not working. This seemed rather strange. They rendered on the screen as hyperlinks (picking up the styling of other anchor tags) however, they did nothing when clicked.

My links were defined as follows in my Razor Page…

<a asp-page="/Index">Home</a>

When viewing the source in Chrome of the rendered page I saw the following…

<a asp-page="/Index">Home</a>

That’s odd! For some mystifying reason the link was not being rendered as expected. This was the first clue though, missing rendering. ASP.NET Core uses the concept of tag helpers which provide a mechanism to write Razor code that later gets rendered at runtime into the final HTML output. Tag Helpers provide a convenient syntax that keeps code in our cshtml files much cleaner. Pre ASP.NET Core we’d have used the @Html.ActionLink method to render a link onto a Razor view based on the controller name and action name for example.

With Tag Helpers we can write code which is much closer to HTML, using the traditional anchor tag <a>. Tag Helpers provide the magic which look for certain tags and then render out the necessary HTML code. In the case above, asp-page should look up the route for the designated Razor Page and render the appropriate href attribute in its place in the final HTML output.

So, it appeared that the Tag Helpers were not working on my Razor Pages. At first I couldn’t think of a reason why this would be the case until I suddenly realised, with Razor we need to make Tag Helpers available using the @addTagHelper directive. This controls in which Tag Helpers are available. In MVC Views this is generally defined in a _ViewImports.cshtml file at the root of the Views folder. This is then inherited on all Views within that folder and it’s sub directories.

I’d wrongly assumed that Pages would also pick up this existing ViewImports file from the Views folder. However, Razor Pages expect their own _ViewImports.cshtml within the Pages folder. In my case, to solve my problem, I simply copied the _ViewImports.cshtml from the Views folder into the Pages folder and tried running my application again. As expected, my anchor links were now rendering as expected. In mixed environments using traditional MVC Views as well as Razor Pages, you’ll need to include _ViewImports.cshtml in both locations.

You can also run into a related issue with missing layout and styling if you do not include a _ViewStart.cshtml file pointing to your shared layout page within your Pages directory too. Note that you can actually use Layouts from within the Views/Shared folder and you do not need to copy these into the Pages folder. Only the _ViewStart.cshtml and _ViewImports.cshtml need to be replicated.


Other posts in the ASP.NET Core Gotchas Series:

No. 1 – Why aren’t my Environment Variables loaded into ASP.NET Core 2.0 configuration on Linux?

No. 2 – Why are settings from launchSettings.json now picked up when using dotnet run?