Tag Archives: Tag Helper not Working

Tag Helper Not Working?

I recently had an issue where I was trying to use a tag helper that wasn’t correctly rendering. The HTML that I had (which was trying to call MyController.MyAction) was this:

            <form asp-controller="My" asp-action="MyAction" method="post">
                <input type="submit" value="Do Crazy Stuff!" />
            </form>

This wasn’t working. The first step when a tag helper isn’t working is always to check the rendered HTML. Tag Helpers should be converted to proper HTML – if they’re actually sat on the page as a tag helper then nothing will happen, because Chrome and Firefox don’t know what the hell a tag helper is.

The rendered HTML should look something like this

<form method="post" action="/My/MyAction">
    <input type="submit" value="Do Crazy Stuff!">
    <input name="__RequestVerificationToken" type="hidden" value="requestverficationtokendsldjlcjsoihcnwoncwoin">
</form>

However, I was seeing the folllowing:

<form asp-controller="My" asp-action="MyAction" method="post">
    <input type="submit" value="Do Crazy Stuff!">
</form>

Like I said – this is no good, as browsers don’t know what to do with “asp-controller” et al.

But Why?

Having done some research, it looks like (pretty much) the only reason for this is that you (or I) don’t have the following line in the _ViewImports file:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Or, if you do have it, then for whatever reason, the _ViewImports file itself can’t be located.

For any Regular Readers* of this blog, you may have noticed this post regarding setting up a project to use feature folders.

One of the interesting features about _ViewImports, is that is applies to the folder that it’s in, and any sub folders; my folder structure looked like this:

- Feature1
-- Index.cshtml
-- Feature1.cshtml
- Feature2
-- Index.cshtml
-- Feature2.cshtml
- Views
-- _ViewImports
-- Shared

As a result, the _ViewImports will only apply inside the Views folder.

The Solution(s)

I can see three possibilities here. Each has benefits and drawbacks.

Create a Symbolic Link

One possibility is to Create a symbolic link between the _ViewImports in the views directory and the feature folder. Launch a command prompt (as admin):

C:\Project\src\MyApp\Feature1>mklink _ViewImports.cshtml ..\Views\_ViewImports.cshtml

symbolic link created for _ViewImports.cshtml <<===>> ..\Views\_ViewImports.cshtml

This works fine, but symbolic links can cause issues; especially if you’re copying code around (for example, with a source control system).

Just copy the file

Obviously, you could simply copy the _ViewImports file to the relevant directory. The benefit of this is that each folder only has the relevant imports for that folder; the downside being that you need to maintain all of these (in practice, the file shouldn’t be huge and complex, so this may be the easiest option).

Parent Directory

Finally, you could simply introduce a parent folder; for example:

- Features
-- _ViewImports
-- Feature1
--- Index.cshtml
--- Feature1.cshtml
-- Feature2
--- Index.cshtml
--- Feature2.cshtml
- Views
-- Shared

This is probably my favourite solution – it gives you the best of both worlds, but it does mean that you need to re-structure your solution.

References

https://docs.microsoft.com/en-us/aspnet/core/mvc/views/layout?view=aspnetcore-3.1

Notes

* I’m curious as to whether anyone does read this on a regular basis. Most of the traffic seems to come from Google. If you are a regular reader then please drop a comment.