Scott Hanselman

ASP.NET 5 (vNext) Work in Progress - Exploring TagHelpers

November 20, 2014 Comment on this post [142] Posted in ASP.NET | ASP.NET MVC
Sponsored By

TagHelpers are a new feature of ASP.NET 5 (formerly and colloquially ASP.NET vNext) but it's taken me (and others) some time to fully digest them and what they mean.

Note that this, and all of ASP.NET 5 is a work in progress. TagHelpers can and will change. There is NO tooling support in Visual Studio for them, as they are changing day to day, so just be aware. That's why this post (and series is called Work in Progress.)

Historically we've used HtmlHelpers within a Razor View, so when you wanted a Label or a TextBox you'd do this. This is from the ASP.NET 5 Starter Web example.

<li>@Html.ActionLink("Home", "Index", "Home")</li>

There you have some HTML, then we start some C# with @ and then switch out. It's inline C#, calling a function that will return HTML.

Here's the same thing, using a TagHelper.

<li><a controller="Home" action="Index">Home</a></li>

The source for TagHelpers is (as with all ASP.NET source) up on GitHub, here. This is an anchor, A, so it'll be in AnchorTagHelper. The code is very simple, in fact, gets a collection of attributes and decides which to act upon.

In this case, "controller" and "action" are not HTML5 attributes, but rather ones that ASP.NET is looking for.

Question for You - Would you rather have these attributes and ones like them (including your own) be prefixed? Perhaps asp:controller or asp-controller? That's an open issue you can comment on! You could do [HtmlAttributeName("asp:whatever")] on a property or [TagName("foo")] for a tag if you liked.

How do these attributes get mapped to a TagHelper? Well, an attribute name is mapped directly to a C# property and automatically injected. See how AnchorTagHelper has public properties Action and Controller?

It's important to note that this isn't the second coming of WebForms controls, while the possible asp:foo syntax may look familiar (even though a prefix is optional.) This is more like syntactic sugar that gives you a compact way to express your intent. It doesn't give you any "control lifecycle" or anything like that.

Personally, I'd love to see them look different in the editor. For example, rather than

Tag Helpers

I'd like to see italics, or maybe a desaturation to show what's server-side and what's not, which will be super important if I'm NOT using a prefix to distinguish my attributes.

Tag Helpers, desaturated

The code below in this Before and After results in the same HTML and the same behavior. A nice aspect of TagHelpers it that you avoid the context switch from markup to C#.

Here is another example, a login partial form, before...

@using System.Security.Principal

@if (User.Identity.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
}
}
else
{
<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}

and after...with the Microsoft.AspNet.Mvc.TagHelpers package added in project.json and then @addtaghelper "MyAssemblyName" in either your ViewStart.cshtml to get this in all views, or separately within a single view page.

@using System.Security.Principal

@if (User.Identity.IsAuthenticated)
{
<form method="post" controller="Account" action="LogOff" id="logoutForm" class="navbar-right">
<ul class="nav navbar-nav navbar-right">
<li>
<a controller="Account" action="Manage" title="Manage">Hello @User.Identity.GetUserName()!</a>
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
</form>
}
else
{
<ul class="nav navbar-nav navbar-right">
<li><a id="registerLink" controller="Account" action="Register">Register</a></li>
<li><a id="loginLink" controller="Account" action="Login">Log in</a></li>
</ul>
}

This makes for much cleaner markup-focused Views. Note that this Sample is a spike that Damian Edwards has on his GitHub, but you have TagHelpers in the Beta 1 build included with Visual Studio 2015 preview or OmniSharp. Get involved!

Remember also to check out http://www.asp.net/vnext and subscribe to my YouTube Channel and this playlist of the ASP.NET Weekly Community Standup. In this episode we talked about TagHelpers in depth!

Related Posts

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
November 20, 2014 5:30
what are the design goals for this feature? I see less razor syntax, but just exchanged for more non-standard html-like markup. I'm still fond of the T4MVC style of referencing controller actions

how about < a asp-href="Home.Index()">Index</ a>
Ken
November 20, 2014 5:35
I like the prefix-less syntax, since the prefix thing seems like a client-side convention (like Angular's ng-whatever syntax), and as you mentioned, the editor can somehow light up the fact that they're "special." The other thing I'd love to see is compile-time errors for bad links. Don't let me publish my app if I changed the name of a controller somewhere and broke links in my views without thinking about it.
November 20, 2014 6:10
So what happens when you have conflicting tag helpers? Who/What decides which helper should render something? On the same topic, what if I want to use two separate tag helpers for the same HTML tag (like one for OK buttons and one for Cancel buttons).
November 20, 2014 7:09
This seems very....angularish. I like it!
November 20, 2014 7:20
Great idea, here's some points:

* defintely would want this prefixed to avoid clashes with other tags and for easy recognition (I like the idea of different styles in the IDE!). From a consistency point of view a simple @ prefix would lend itself as it is already a the prefix for any server side releavant items

* are these tags rendered on the client side? if not do we have an option to carry them on to the client side?

* I'm wondering though whether we need to have the separate controller tag, wouldn't a simple punctuated qualification like action="controller.action" be shorter and easier to read?

* you mention the relation between tag name and class that implements it. How would we go about providing the same funcitonality to a number of different tags?

Thanks!
November 20, 2014 7:21
I like, however I'd love to have some type safety and refactoring support like we had with expressions in mvc futures back in the day...
November 20, 2014 7:26
This seems very tough to get on-board with. My biggest concern is how do we easily discern between which more obscure attributes are "TagHelper" related vs which ones are part of the HTML spec? When my company hires new devs, I can't rely on the fact that they would realize that "action" is a "server-side" attribute, but then things like "media" and "type" are HTML ... not to mention how hard it would be to tell the difference if I'm trying to maintain code where folks have mixed server-side/html attributes, eg:

< a action="index" target="_blank" controller="home" >

I love the idea of knowing exactly which method/constructor is being called when I use Razor (eg. @Html.DoSomethingThatICanDebugEasily() ), but having to remember what TagHelper maps to what tags seems like it could be a bit of cognitive overload (especially on larger apps).

Maybe something that still embraces the @ symbol?

< @MyNamespace.TagHelper(new { option1 = "optionVal" }) html-attribute-1="attribute-val" >
November 20, 2014 7:38
Thank you for this. The UI designers at work don't understand Razor.
November 20, 2014 8:09
Maybe you could let the dev know its server side by having a `runat="server"` attribute? :) In all seriousness this most certainly seems like the second coming of Web Forms. Not that that is necessarily a terrible thing, as both MVC and Web Forms have their strengths and weaknesses.

Once you introduce this syntax back into the platform its only a matter of time before devs start adding back all the stuff from Web Forms that they were fond of.
Sam
November 20, 2014 8:31
Seems very similar to the SparkViewEngine's notion of bindings. I like it though.
November 20, 2014 8:38
Regarding "the open issue you can comment on": I wonder what would happen if the W3C decides to add an action or controller ... attribute to some html tags ... Would I have to change my old code if I want to use these new features? Would I have to prefix them with html: ... Would I even be able to use these new features without the proposed "extension" ... Looks nice but doesn't feel right to me! I'd prefer a namespace prefix - that's what they are for!

BTW, Mr. Hanselman, you're one of my favorite authors in tech! It had to be said ... ;)
November 20, 2014 8:40
Not a fan... too difficult to tell the difference between server and client side. @: is plain text, but I'd rather see something like that @:controller="blah". All other server side/C# things have the @symbol... it actually seems more complicated to omit it for some times of server side things.
November 20, 2014 9:16
I like how data attributes are added to html elements. Maybe something like asp-controller and asp-action would be easier to follow.
November 20, 2014 10:35
Good way. Far better than the razor syntax.

Standard HTML "data-" attributes should be preferred for prefixing along with "ASP" specific string to distinguish.

e.g.:
... a data-asp-controller="" data-asp-action="" ...


This will feel more natural, semantic and play along nicely with HTML. Although a little verbose, I feel this should be the way forward rather than obscure custom prefixes. Without prefixes it just feels like webforms.
November 20, 2014 10:37
I agree with Eric, it breaks separation of concerns, perhaps it needs a prefix.

Just my opinion.
November 20, 2014 10:43
Excellent idea, I think that for standard tag attributes like href, action it should remains as it is but for specific like controller it is better to have some prefix. Without prefix it can be confusing when you read a code and rise a question like 'what from this attribute from, who use it?'.

Can we use data-asp-... ?
November 20, 2014 10:47
The custom tags definitely need some sort of visual identification to distinguish from HTML tags; and something more visual then just dimming or changing colour - think accessibility. A prefix of some description would be my preferred option; either bring back good ol' asp: or if you think that'll freak out people who thought they had seen the last of WebForms, then asp-.

It'll save a lot of trouble with custom HTML tags and attributes in the future, and make it more obvious where code is coming from if you're not using Visual Studio with some tool like Resharper.
November 20, 2014 11:14
I like not having any technical restriction on tag helper names, but it would be nice if the built in ones had a prefix like asp-*

Also, I've asked this before and I know there is no tooling yet, but please consider having a way to provide custom intellisense for a taghelper (like for cms keys or whatever) beeing able to supply squiggles would also be awesome :)

Is the tooling in general open source as well by the way? I looked in the repos but I wasn't able to find it
aL
November 20, 2014 11:33
I agree with many comments here. Prefix should be added to these tags to remove confusion. Its okay to see these in visual studio but consider if someone is checking the code on notepad or github this makes it pretty confusing for readers.
November 20, 2014 11:37
I think we definitely need some visual clue about which attributes have a server-side effect, and this should ideally be visible without an IDE . So YES for the prefix! I quite like the idea of prefixing those attributes with a @ , it's explicit enough to understand that this is razor, and short enough that it's not a pain to type. Plus it could help to trigger intellisense with only attributes that make sense.
what about all the other attributes one can add to a tag ? Are they sent "as is" to the client ? Does the tag helper see them ? Can you have different tag helpers bound to the same tag? What would happen then ?
November 20, 2014 12:00
These TagHelpers make the html more readable, so very nice new feature.

I'd like to see a prefix on the attributes, one like data-asp-*. In that way the page is always valid HTML5, before and after rendering.

For example in case a helper for a certain tag doesn't exist, the html at the client side just contains an valid data-* attribute.
November 20, 2014 12:04
Clever, but I'm not sure If I like it. I appreciate when there's a clear distinction between my client markup, and server code.
November 20, 2014 12:11
What about enabling both? If someone want there to be an explicit prefix, he/she could have one. If not - it could be just skipped. Something like "AutoEventWireUp" type of option.
November 20, 2014 12:26
All of these methods just return the href on the client side.
In my opinion the best solution is the implementation of the validation of of href and controller-action relationship.
It seems that multiple custom tags - is not the best solution, and I would like to avoid them as much as possible.
November 20, 2014 12:34
Lost some text.

All of these methods just return the href on the client side.
In my opinion the best solution is the implementation of the validation of href and controller-action conformity in IDE, when developer write "href" tag.
It seems that multiple custom tags - is not the best solution, and I would like to avoid them as much as possible.
November 20, 2014 12:41
I think its doesn't need. This syntax sugar add more complexity to understand markup. Its smooth border between plain html and server code, it became more implicit.

IMHO razor syntax is good enough for today and tomorrow web techs. I would be better if MS will focus on things like:
- performance (small sites should run fast and need less memory)
- portability (i want to run simple sites on cheap linux hosting, and deploy using web deploy:)
- make iis faster
- more diagnostic tool for asp.net mvc, and iis
November 20, 2014 12:44
One argument for having a prefix is that it will be more obvious for people not developing in VS. Our front end devs would like to be able to use an alternative IDE, so without a prefix the server side transformations would be very easily lost in the other attributes.
November 20, 2014 12:49
How about a prefix that is not valid HTML. Something like :controller="Home" :action="Index" or similar.
November 20, 2014 12:56
In this particular case I would choose
T4MVC all day!

< a href="@MVC.Home.Index()">Index</ a>

In other cass I would like to see some prefix, just @. We all know @ stands for serverside code. No need to compete with real html attributes. No confusion.

// Ryan
November 20, 2014 13:28
I'm not sure this is such a great idea. Tag helpers make differentiating between server-side and client-side attributes harder than it should be. I'd rather favor explicitness (opaque Razor code) over implicitness (transparent tag helpers).
November 20, 2014 13:38
I got same question as @Harald Mühlhoff, what if W3C adds new attributes like controller, action etc to HTML?
November 20, 2014 13:56
I have to say I don't like this at all. You guys are mixing server side with client side. And isn't it really much easier to just go with:

< a href="@Home.Index()">Home</a>

Today I use:

< a href="@Url.RouteUrl("Home")">Home</a>

It's still shorter and more readable than:

< a controller="Home" action="Index">Home</a>

I don't use controller/action routes that much, but instead give my actions a name using attribute based routing.
November 20, 2014 14:16
Use prefixes for anything that's not standard HTML. How do you know I'm not using a client side JS lib that acts on these same attributes?

Both asp-controller or asp:controller would do. I personally prefer the first one as people won't confuse it with previous WebForms stuff.
November 20, 2014 14:31
I've never been a fan with how the html helpers work. Too many overloads.

imho they're screaming for a fluent interface and always have been. Something like the FluentHtmlHelpers class in contrib, but without insisting on a different page inheritance.

[/my2pworth]

FJ
November 20, 2014 14:40
I don't like this as well. It makes it hard to differentiate between server-side code and the html markup. If you ever have to maintain someone elses code it's going to be easy to miss which tags are actually static html and which ones are generating markup.

You could use <asp:controller> or runat="server" but then you've just come full-circle and re-invented server side tags.
Joe
November 20, 2014 14:46
I keep going back and forth. The tag helpers look similar to my experience with Handlebars JS, and I like how that works. I also see merit in the comment about breaking separation of concerns.

If the Tag Helpers get color coded in the IDE, would that cause confusion with developers with color vision issues (i.e. me)?
November 20, 2014 14:47
I don't like the sound of this. Love the idea of a view engine which is more like Angular but I don't want to see this mixed in with Razor
November 20, 2014 14:52
To be honest I prefer Razor to remain distinct from HTML 5. Interspersing new pseudo tags so I can get something that "looks" like HTML 5 provides no real benefit. The distinctions are important when troubleshooting.
November 20, 2014 15:24
are there any other changes for other helpers? how would DropDownFor would look like ? will I need to iterate with a list adding options to it ?
November 20, 2014 15:39
I'm not a fan of HtmlHelpers :) I like tagHelpers feature, AngularJS oriented ~ improve html5 tag, but with a prefix asp-... or mvc-... or something like this.
November 20, 2014 15:52
Feels a bit like Spark (if you remember that view engine) and I think that's a good thing as it always felt like a more natural templating engine than Razor...
November 20, 2014 16:05
Love it. I've stopped using @Html.ActionLink because if you need to add just simple extra thing, you end up typing far more and more error prone (like your sample Log in button)
November 20, 2014 16:07
If we are going to introduce additional asp or mvc specific attribute tags, there should be a prefix, as readability and purpose of those tags should be differentiated from common html.

With that being said, I would rather see a dot notation syntax such as Home.Index() that is fluently-driven.
November 20, 2014 16:13
How about

controller="@Account" action="@Manage" title="Manage" and then make @Account, @Manage yellow in the IDE
Per
November 20, 2014 16:59
I think I would prefer a syntax of asp- for any tag helpers. I also think that the server should use the routing engine to make this less wordy.

asp-href="Home/Index" would be my suggestion.

or even

asp-href="Products/Edit/1234#description"

If we're going to go down this route, let's really put the server to work. The server knows how to parse a url like above and can take what I write and spit out a fully qualified url. This could really come in handy when using areas. My view no longer has to know what area it is in. The server could determine that for me (or maybe I'm just really wrong about that).
November 20, 2014 17:09
Definitely with a prefix of some kind - maybe a razor-like @controller="Home" or something - I'd want to be able to scan-read and see what is going to get rendered and what is going to be processed on the server. I currently very rarely use HTML helpers, I normally use Url.Action to populate the href attribute.

Also what is the plan for using url parameters with this approach? I guess you could do something like: @controller = "Widget" @action = "Details" @parameters = new { Id = 123 } ?
November 20, 2014 17:42
I've always hated html helpers in Razor so this sounds perfect. Would definitely want a prefix though otherwise there will almost certainly be a conflict at some point.
Tim
November 20, 2014 17:42
Maybe this has been asked before, I haven't read all of the comments, but is there some opt-out option for TagHelpers? What 'triggers' a tag helper to be called? Is is only based on the element name?

What if I don't want my labels, anchors, etc. to go through all of the tag helper code / pipeline, I only want my anchors to be rendered to the client as normal?
November 20, 2014 17:45
Another thought... will these play nicely with Attribute routes (I'd guess not)? With WebApi routes (I'd guess yes)?
November 20, 2014 17:48
I have to agree with @Ken and @Ryan, t4mvc is the way to go. Strongly typed, compile time checked links which will update dynamically if ever your routes are changed. I think string based controller and action attributes are a backwards step.

Really simple demo video here

I'm sure the syntax could be simplified even further, and maybe even remove the need for the t4 generated files altogether?

November 20, 2014 17:51
The tagHelper looks really nice.
November 20, 2014 18:32
It really does look a lot cleaner but I'm not sure that's an advantage. Because it's also important to show clearly when code is very different and that desaturation example doesn't look like enough of a difference.

I would want a complete different tag. Having the same html markup like an anchor tag with only different attributes is going to lead to a lot of "what am I missing, it's right in front of me"-like debugging.

My $0.02

Thanks
November 20, 2014 18:37
Yes, please prefix these attributes! Even if you don't, I think they need to at least appear different in the intellisense list (and you may want them to anyway).
November 20, 2014 18:57
I think the attributes need a prefix too. asp-* is fine. data-asp-* seems unnecessary (leave data-* for client-side attributes, assuming these attributes are not rendered on the client).

What happens if I do something like < a controller="Home" action="Index" href="foo">Home< /a>? Would the controller and action override the href or would the href take precedence?

Can I specify variables in these attributes e.g. < a action="@prevAction">?

How would route values be provided using tag helpers?
November 20, 2014 19:00
This feels like JSTL from Java which is, in my opinion, one of only areas that I have always felt Java has gotten it better that ASP.NET. They use prefixes to denote the different context (which is, after all, the purpose). I think that <form> as HTML tag and <asp:form> as Razor tag gives better hinting to code maintainers about what is going on. As an enterprise developer, maintainability matters.

If I were making the call, I would keep the @ syntax and add in the tag helpers with namespace prefixes ala JSTL (https://jstl.java.net/)
November 20, 2014 19:17
I like it. Definitely makes it prettier. I think asp-controller and asp-action would be better than just controller and action though.
November 20, 2014 19:32
Seem great idea , I never liked the Html.Dosomething way of rendering html tags
Sam
November 20, 2014 19:36
As with others, I personally prefer the clear distinction between client-side markup and server-side code that Razor provides, rather than annotating client-side markup with server-side attributes. Now there's potential ambiguity for both the developer and the UI designer.
November 20, 2014 20:37
One thing that I really like about the HTML helpers is the fact that they are extension methods, which means that I can make my own extension methods for HtmlHelper and create my own custom helpers. Are the TagHelpers extensible? How would I make my own TagHelpers (without digging into the source of the TagHelpers themselves)?
November 20, 2014 21:36
Agree with Bobo: Type safety, refactoring and |Find Usages' support are desirable.
November 20, 2014 22:56
Add me to the giant list of people that think this needs to at the very least be prefixed. I'm of the opinion that I don't want things directly in the HTML markup that can't be understood client side (what if that HTML accidentally "leaked" outside of a Razor view for instance, say in copy-pasta). Maybe if the TagHelpers also provided unobtrusive JS to do their thing I'd feel less squicky about them in my markup.

Also, for prefix suggestions: @- is not currently valid in Razor it seems. It would feel enough like data- and its ilk that it would feel somewhat reasonable for HTML5:


&lt;a @-action="Index" @-controller="Home"&gt;
November 20, 2014 22:59

Not a fan - for the same reasons already outlined


  • Hard to distinguish between client side / server side

  • Too magical if something isn't working

  • Parameters don't look like they'd come out nicely



The < a href="@Account.Manage()">Hello @User.Identity.GetUserName()!< /a> syntax fixes all of that.

Plus they work nicely with BuildViews=true and can work nicely with refactoring (not saying TagHelpers won't, it just doesn't seem likely)
November 20, 2014 23:26
I can just imagine a junior dev looking at the tag helpers and thinking this is a new HTML5 attribute of which they weren't aware and then misusing that mistaken "knowledge". While I appreciate the cleaner look I think the use of Tag Helpers is asking for trouble and I would lobby to have them banned in my shop.
November 20, 2014 23:47
Wasn't one of the design goals of MVC that the HTML you write in the template was exactly what you got when rendered in the browser? This Tag Helpers idea is a throwback to Web Forms where what you write in the template ISN'T what you get in the browser. Along the lines of what someone mentioned earlier, a markup style like:

< a href="@Url.Map(controllerName, actionName[, parametersDictionary])">link text< /a>

makes a lot more sense. The designers and junior devs know which part is HTML, which is code, and it's clean and expressive.
November 20, 2014 23:50
Vote for prefix
November 21, 2014 0:05
TagHelpers will make the HTML tooling a lot simpler because it will always be dealing with markup rather than lots of the current HTML helpers for simple tags like forms and links.

This also invites plugins which have TagHelpers for generating markup for Angular or JSX for example. It also means we don't need to keep creating more HTMLHelper extensions for every new web component that needs some server data to render.

Regarding the prefixing, the tag itself should have a prefix eg @<a controller= so that it's easy to tell when the markup has "opted in" to a TagHelper. Prefably configurable of course so we can choose!
November 21, 2014 0:18
I would vote for not making the controller and action based on attributes. The separation of server code and client is clearer with the razor syntax. Though if the goal is to let these be optionally processed by a Javascript framework, that would be interesting. If this is just an additional way to do it I would vote for a prefix.
November 21, 2014 0:29
I would like to see something like JSX (http://facebook.github.io/react/index.html) for C# instead of Razor. Maybe based on Roslyn.
November 21, 2014 2:32
This feels like a backward step to me (with or without the prefix).

It is effectively pure markup, but that markup is now being altered in ways my eyes would probably miss if I'm not careful. The rendering engine would remove the "controller" and "action" attributes and add an "href" in their place? What's wrong with using what we want?
ie plain old href and helpers for determining the url?

Unnecessary complication.
It's not even syntactic sugar - it's syntactic liver.
November 21, 2014 2:53
Lots of smarter people than me have said wonderful things, so I'll add to the tally that says yes to a prefix, with a penchant towards "asp-*"
November 21, 2014 4:57
I hope that feedback has been obvious enough in the comments here for Damian that attributes are problematic. You can get away with yet-another-prefix though as the same comments suggested.

I can see why you don't want prefix, and I hope you see why attributes not showing which is on server and which conflicts with client side etc is a problem.

I wonder how many designers vs developers use Razor. Razor is code focused. It's designed to be so and people used it as so. If I wanted a markup focused thing, I'd look at Spark View Engine. Likewise, if you wanted to make Razor more markup focused, you'd look at what Spark View Engine did in that area. However, that markup thingy didn't fly too high obviously so why bother?

And similarly, if we all wanted to embrace the code focus of Razor rather than reduce it, we'd be looking at something like HtmlTags, which Damian seems to refuse to check (I asked him wehther he did, he said no).

I hope someone is listening to these comments, and I mean thoughtfully.

Thanks for trying to solve the silly links and forms syntax though.
November 21, 2014 7:06
I completely agree with Mohamed Meligy here. He is right as people use Razor because it is code focused. I think if you need to rely on an editor to differentiate between a regular markup and TagHelper as you have suggested in your article than it indicate that its already confusing.


I think there is not need for the TagHelper rather we need to get rid of the magical string for controller and action name. It would be great if it could be replaced with some sort of lambdas.


November 21, 2014 10:33
Please +1 vote for T4MVC as as HTML attributes are for HTML, not ASP.NET MVC.

I can see bugs created by generic attribute names. With the below code, the server vs client code is clear:

< a href="@MVC.Dinners.Delete" data-id="@MVC.Model.Id" foo="@MVC.Model.MyFoo" bar="7" alt="Just better" target="@MVC.Model.TargetType">@MVC.Model.LinkName - Go!</ a>
November 21, 2014 11:37
Great idea. TagHelpers are just like standard HTML markups. But I would vote for a prefix or somekind of mechanism to differentiate TagHelpers' attributes from standard HTML ones.
November 21, 2014 12:47
Definitely not a fan of this for the reasons already stated.

I love what MS are doing these days but this is one of those cases where they are making a feature desperately searching for a problem.

I already have a hard enough time explaining what HTML is vs what asp.net code is to students. We don't really need additional "magic" to confuse the matter further

Cheers
November 21, 2014 13:01
Whi not allow to opt-in the tag helper with a special using?
like this

@using prefix=Asp.TagHelper;

so one can choose the prefix it wants, or no prefix at all to have all automatic?

for example it could be

@using prefix=Asp.TagHelper;

<prefix:a href="link.html" prefix:controller="Home">Link</a>

and it could also be

@using Asp.TagHelper

< a href="link.html" controller="Home">Link</a>

Or withaout opting Tag Helper in, simply and plain HTML

< a href="link.html" >Link</a> @*it is the plain anchor tag because no helper was opted in*@
November 21, 2014 13:26
I still like the '@' as an indicator of server side code running and so blending server side code within the html without any clear indicators may prove difficult to read, debug and separate. So minimal prefix gets my vote.
November 21, 2014 13:32
My 2 cents: I don't dislike it, but a prefix is definitely needed, because I might be working with some JavaScript library that uses the same "action" attribute maybe.

Also, make the prefix use a colon, not a dash: dashes are used in all client side libraries that define custom attributes (see Angular), so seeing a colon quickly helps to understand it's server side stuff. But please use something else than asp:controller, it might alienate developers who thought the old classic asp had finally died! Go for mvc: or razor: or rzr: or something like that.
November 21, 2014 15:32
Not a fan - smells like web forms 5.0. Why not simply < a href="@Link.Home.Index">Home< /a > instead? Better intellisense support, compile time checking, consistency etc?
November 21, 2014 16:34
How exactly would you pass parameters to the action with tag helpers for example if we are traying to something like @Html.ActionLink("Details", "Foo", new { id = 5, color = "red" })? Would these be data- attributes or something else?
November 21, 2014 16:39
Yuck! Def. don't like... as already mentioned by others, this just smells like history repeating itself instead of actually making progress (yes, its you WebForms i'm thinking about).

And whats the workflow to figuring out if and what TagHelpers will be invoked in this given context and what properties they have and what they mean. Making Intellisense work for this seems clumsy, and how is typesafety and refactoring going to catch if a property is being renamed or removed on a TagHelper?

HtmlHelpers as method calls is the way to go IMO.
November 21, 2014 16:44
Not a very good idea as it is right now, I think you need to add something to make it different from standard HTML markup.

I definitely like < a @controller="Home" @action="Index">Home< /a> or < a @action="Home.Index">Home< /a> as suggested above... I'd like keeping the "@" symbol as a Razor thingie.
November 21, 2014 17:19
I love the idea of continuing the scraping back of server-side tags and the return to the HTML bare metal. It's great to see this journey continue from Web Forms controls, to MVC HtmlHelpers to annotated HTML attributes. However, I completely agree with those who have pointed out the potential confusion of mixing server-side attributes freely with HTML attributes, and I think any confusion could be easily sidestepped by prefixing the server attributes with '@'. I do like the idea of 'controller' and 'action' attributes but to an extent this is throwing out the baby with the bathwater, if we have to also lose the MVC route convention (e.g., '~/Account/Login'). Why not just add a '@route' parameter for those who want that -- e.g., <a @route="~/Account/Login">log in</a>.

I am wondering how well tag helpers will handle selects and options, though....
November 21, 2014 17:39
I've now watched the part about TagHelpers a few times in the ASP.NET Community Standup, especially about how Intellisense and typesafety is going to work.

I have to admit that i dislike the whole idea less after letting it sink in, but i agree with everyone asking for a explicit prefix for either the whole tag or each attribute.
November 21, 2014 17:59
Personally I think a combination of a something like an "asp:" prefix AND the colour desaturation in the IDE would be ideal, so that they are recognizable even in a plain text editor.

The prefix would also solve the issue of separation between standard HTML5 attributes and TagHelpers.
November 21, 2014 18:13
At last .... the reintroduction of server side controls. How I've missed them.
Tom
November 21, 2014 19:20
Welcome to MVCForms!

Many have been bashing WebForms in favor of MVC and, all the time, running to WebForms.

Done great things in the past with tag mapping in WebForms.
November 21, 2014 20:50
I like the idea, but I agree with many others that a prefix should be used.

Prefixes makes it easier to see what belongs to HTML and what is added to it.
November 21, 2014 21:56
Prefix, preferably something standard in HTML so that other IDE can deal with. Strongly typed, compile time checked and this is win. I don't like HTML helpers' over reliance on so many strings overloaded methods.

November 21, 2014 22:19
I'd say that prefixing with the data-asp-* attribute, that others are suggesting, would be the way to go. But what happens when you want to send some data-asp-* attribute? I think something like asp-* would be fine, knowing that these attributes wouldn't be sent to the client. In the <form/> example you give above there is the collision of the action attribute, where asp-action would disambiguate these two attributes.
November 21, 2014 22:30
Prefix! Just to avoid collisions with other toolsets
November 21, 2014 23:10
I like the implementation of Tag Helper but still I love @ (HTML Helper) symbol.
November 21, 2014 23:17
It's looking good in the comparison of before and after but it is missing the Html-javascript (client side) and razor, still most people don't use data- prefix with their attributes.

I think @ will be better as the prefix of tagHelper property, because @ is already belongs to Razor syntax. or at least it should be optional for developers to have @ as prefix for tagHepers.

If i will write an anchor tag as < a id="registerLink" @controller="Account" @action="Register" data-wz-animate="zoomOut">Register< /a> will also allow others to differentiate among Html, angular and Razor attributes.

From one of Asp.net Weekly Community Standup, I remembered, tagHelpers are being introduced because of data- prefix and anuglar directives attributes are hard to write with the "Razor syntax" like @Html.Action("Home", "Index", new { data_wz_animate="zoomOut") and also looks odd. So the solution should be resemble to Razor syntax.
November 22, 2014 2:26
Directives for Razor:P.. cool
November 22, 2014 3:08
I really don't like this, especially the asp: or some other prefix suggestion.
Many developers are still naming their ID and class with pascal case naming (because of web forms and win forms convention) instead separating words in ID and class names by a hyphen ID and Class Name Delimiters.

Current HtmlHelpers are clean and simple and explicit that something is Razor code.
November 22, 2014 4:46
I like the idea with a prefix. It is easier to distinguish and also easier to do custom tag if we would like.
Thus it would be possible to have "virtual" tags that would translate to one or more real tags (or even none if we decide so)

For links, it would be nice if controller and action would validate against actual action. Maybe something like : ControllerName, x => x.Action(p1, p2, p3).

And it should also update with refactoring if the method or controller is renamed.
November 22, 2014 5:19
I agree with the general sentiment here that prefix-less attributes is a very bad idea. I would even go further and say that any non-html values in a link are wrong. Why can't we just have an href-attribute with the plain path?

Since routes are all defined inside the same project, the tooling could figure out which paths are valid and which are not. It could provide intellisense (aka a list of all valid routes) when you open an href-attribute. The list of possible values, should obviously include MVC-routes, Web api routes, static files and the bunch.

This makes it effectively what you see is what you get, and at the same time provides help to the developers.

I'm not saying this is easy, I'm saying how I'd like it :-)

Since I'm in asking mode, it would be nice if when you rename an action, the tooling could figure out which href-attributes are affected and rewrite them as well.

The only issue I see is with virtual directories, but you could do something with a prefix like href="*/some/path/that/is/not/recognized" or something similar.
November 22, 2014 7:06
You're miss @Html.AntiForgeryToken() in second sample
November 22, 2014 13:36
@Alex no he didn't miss it, it is generated implicitly by the tag helper for the form attribute, that's the point!
November 22, 2014 19:19
Hi there,

If attributes were prefixed with the @ (ex: @controller="foo") the yellow highlight on the @ char would be enough, and no desaturation of asp attributes were need.

Regards
November 23, 2014 3:04
< a @action="Home">link to Home.Index()< /a>

< a @action="Account.Login">Login< /a>

This is how I see a links)
November 23, 2014 11:07
This seems to work fine for simpler controller/action routes, but what about routes with parameters? Seems like you might have to come up with some complicated syntax to represent the current style:

new {id=1, param2=x, param3=y}


Also, how would attribute based routing fit into this? There may not be a controller or action defined. There may however be a route name.
November 23, 2014 11:10
On the topic of html generation though, I really like the way Fubu Html Tags work. The tag generators are composable so it's easy to add extra attributes/classes/etc onto the end of any helpers you've defined in a strongly typed way. Would be great if the built in Razor HTML helpers were built in the same way!
November 23, 2014 16:36
@addtaghelper "MyAssemblyName" will register tag helpers in your assembly. To get the built-in tag helpers do you not need a @addtaghelper "Microsoft.AspNet.Mvc.TagHelpers"?
November 24, 2014 0:17
Is there a timeline on the release of ASP.NET 5.0?
November 24, 2014 5:51
I really don't like the idea server-side asp directives/syntax masquerading as HTML. If you must do taghelpers at least use some sort of prefix e.g. @ or asp-controller or asp:controller.

BTW I like existing Html helper. The main problem I have with Html helper is the crazy number of overloads that still don't cover all the combinations (see questions on SO about folks want to add form attributes with @Html.BeginForm). I think some of the issues with the existing Html helper could be solved by adding an overload for each tag that uses optional parameters. That would be the one and only overload (per tag) that folks would ever need.
November 24, 2014 6:25
To echo many people here already, go for prefixing the tags. It may be a pain to add, but I think that it would be worth it in the end.
November 24, 2014 15:50
There are a number of problems with this approach.

1: Code is written to be read and debugged. It should be obvious at a glance whether something is client or server-side. A prefix would begin to help this issue, but only solves the property side of the equation, not setting a value. You're already going to have @blah statements in the code as values are output, so it would make the most sense to us a @ prefix on the server-side attributes as well, as we have already trained our eyes to look for those when reading razor templates.

2: This method is parsing client-side code, interpreting it, and then outputting new client-side code. I don't want the engine to alter my client-side code. That's why I chose to use client-side code instead of helpers. I don't want to have to go back into the Web Forms mode of wondering whether the HTML/tags I think I am outputting are the ones that are actually being sent to browsers, in case someone tries to be helpful again and alter my content mid-stream for "better compatibility". Or a new attribute is created that collides with the ones that ASP.Net is specifically looking for. Or I'm not writing HTML at all and run into collisions/errors due to the system assuming I only ever outputting HTML.

3: A later error or difference introduced into this parsing and output is going to introduce bugs into stable, production applications (since it is transforming code for the client instead of just evaluating tokens and code sections)

4: It will be inconsistent. Some of these things are attributes, but a lot more of them are attribute values. So back to the @prefix, instead of having 2 methods of identifying server-side items, you would have one. And at that point, why even make it look like an attribute? Why not have an anchor tag with @Mvc.HrefFromAction('controller','action') inline in it? All the HTML, with sprinkled output methods that generate just a single clientside attribute and value (and don't require evaluating all of the attributes and determining which ones have special meaning and which get passthrough).
November 24, 2014 19:02
As some people have already asked, how do you pass action parameters using Tag Helpers?

If the answer is "You Can't" then what's point of tag helpers? Why not use static html?
Joe
November 24, 2014 21:24
Looks like a great feature.

I would say having a prefix would help it to not get confused with HTML attributes for developers who are not using VS.

But more importantly could you guys do something to remove the magic strings and support the way of T4MVC (as a standard across all .NET languages)? Pretty please! :)
November 25, 2014 5:57
A long read through comments on the github issue tells you how confusing those Razor HtmlHelpers are. This is not turning good!

Interestingly no one from the team seems to be helping with the confusion as well. Just cracking through the other issues and *looking like* this one is ignored.

I know it's optional and all, but optional could always be an excuse for bloat.
November 25, 2014 6:19

@{
var linkA = Url.Action("DoSomethingA","ControllerA");
var linkB = Url.Action("DoSomethingB","ControllerB");
}
< a href="@linkA" > do something A </ a>
< a href="@linkB" > do something B </ a>


Why not just declare variables on top of a view .cshtml and use them like shown above? Easier to read, understand, refactor, debug, and maintain.

Better yet, can we have such syntax that support refactoring and intellisense?
< a href="@ControllerA.DoSomethingA" > do something A </ a>
If we can do it on Model, why not on Controller? Framework should help a developer more productive by taking care of such boilerplate codes. Framework should not force a developer to type boilerplate codes (be it C# or XML/HTML attributes) again and again.

TagHelpers are not 'Convention over Configuration'. It is going backward to configuration over convention. I personally do not want to type 'controller', 'action' again and again inside every hyperlink. It does not add any value.

Imagine seeing multiple framework's custom 'tag helper' attributes inside one single HTML tag (ASP.NET MVC, Angular JS, etc)...I see spaghetti codes.
November 25, 2014 14:46
I like the idea of prefixing the tags, but why not take it one step further and have a XAML type syntax that renders to html, but allows you to group tags, and limit your intellisense options based on the control type?

eg:
< a ...>
<a:bootstrap:tooltip tooltip="this is a tooltip" position="top" />
<a:bootstrap:style class="btn-sm btn-warn" />
<a:mvc:routing controller="someController" action="someAction" />
etc.
< /a>

November 25, 2014 16:54
I don't get it, maybe getting a little old.

This: @Html.ActionLink("Home", "Index", "Home")
can be written as: < a href="Home/Index">Home</ a>

This: < a controller="Home" action="Index">Home</ a>
can be written as: < a href="Home/Index">Home</ a>

This:
<form method="post" controller="Account" action="LogOff" id="logoutForm" class="navbar-right">

can be written as this:
<form method="post" action="Account/LogOff" id="logoutForm" class="navbar-right">


If you want a dynamic href/action then just define a variable:

@{
var path = "Account/Logoff";
}

< li>< a href="@path">Home</ a></ li>
<form method="post" action="@path" id="logoutForm" class="navbar-right">
November 25, 2014 20:28
@Kevin:

You shouldn't be hard coding the url. Your example could be changed to:

< a href="@Url.Action("Index", "Home")">Home</ a>

This allows you to update your routes and the urls will automatically be updated. However the anchor tag is not the best example of where this shines. Image a textbox like:

@Html.TextBoxFor(m => m.Name, new { id = "name", @class = "name", data_title = "Title Here" })

This could be rewritten as:

<input class="name" data-title="Title Here" for="Name" id="name" type="text" />

This has a bunch of improvements:


  1. You don't have to use an anonymous object to specify the attributes

  2. You don't have issues with c# keywords such as "class"

  3. You would get intellisense for the classes from your style sheet

  4. You don't have to deal with underscore hack to specify HTML 5 data attributes

  5. It's a lot more readable and looks more like the HTML that's rendered



Hope this makes things a little clearer.
November 25, 2014 22:36
@LeeTimmins I'd wager that most people rename the action or move it to another controller whenever they change the route, you still have the same magic strings that need updating.

What we need is compile time checked routes, at least for the simple cases. Like T4MVC
November 25, 2014 23:47
A prefix would probably make sense (similar to angular's "ng-"). Although for some reason I don't like the sound of having a "asp-" prefix either.
November 26, 2014 0:00
I think I agree with having a @controller and @action.
November 26, 2014 0:08
I add my vote to a T4MVC style approach - as pointed out in previous comments, why not do it properly, and give compile time checking. refactoring support, and why are we now talking about adding more magic strings?

It would be a mistake to try to add something which is ´Angular like´, as Angular itself is moving away from this in version 2 anyway. For example, the proposed syntax is now:

<div [ng-repeat|todo]="todosOf('good')">

and

<button (click)="deleteTodo(todo)">

So, it is going to be messy anyway...

Microsoft should really step back and stop chasing open source web development trends, which are complete chaos - start making the trends yourself! Think of the best way to do it, make it opinionated, coherent within the Microsoft toolset, and extensible. Visual Studio 2015 with NuGet, but then Bower, NPM, Grunt, etc - is already shaping up to be an embarrassment, as many people are already moving on to other Next Big Things (for this week).

Dont make life difficult for your existing customers, in a plaintive attempt to chase after a few more new customers, who are already hostile to Microsoft. Copy what they have already, and they will ignore you. Build something better, and they will come.
November 26, 2014 20:42
Please don't forget about areas. Support for areas in MVC 5 still feels second class. Perhaps that can be addressed in vNext.
November 26, 2014 21:39
I suggested to rename Tag Helpers to Tag Filters or something more appropriate. Please join the conversation on GitHub if you have an opinion on that.
November 27, 2014 18:24
This looks like a step backwards to the old days of ASP.NET Web Forms.

Let use stick to being able to see whats code and whats html without highlighting
November 28, 2014 20:25
I think it's a step back. It feels like WebForms is comming back.
Keep things simple. Make the syntax simpler not more complicated.
We don't need more server side stuff inside markup. Build better helpers with a human API.

Please do note fix what is not broken.
November 29, 2014 22:54
@David:

Microsoft should really step back and stop chasing open source web development trends, which are complete chaos - start making the trends yourself! Think of the best way to do it, make it opinionated, coherent within the Microsoft toolset, and extensible. Visual Studio 2015 with NuGet, but then Bower, NPM, Grunt, etc - is already shaping up to be an embarrassment, as many people are already moving on to other Next Big Things (for this week).

Dont make life difficult for your existing customers, in a plaintive attempt to chase after a few more new customers, who are already hostile to Microsoft. Copy what they have already, and they will ignore you. Build something better, and they will come.

Well put! That is exactly what this feels like to me. As an ASP.NET MVC dev for about 4 years, I look at vNext and think WTF? There's a whole lotta change here - some good (xcopy deployable .NET core) and some questionable (taghelpers). This much change risks alienating existing MVC devs.

If Microsoft can somehow successfully keep their current crop of MVC devs happy while reaching across to the hostile, non-MS web devs - well more power to them. I'm skeptical though. I observed a similar attempt with WinRT to woo MS hostile devs with a Html/JavaScript/CSS stack. I'm not sure that strategy paid off. The Windows Store doesn't seem particularly healthy to me and from what I've heard, north of 80% of store apps are written in C#/XAML.
December 01, 2014 2:14
Is there any way to make the tags have some kind of compile-time checking (without turning view compilation on)? That would be important for me personally, one of the problems with @Html.Action() is you go back to the stringily-typed land of Javascript.
December 02, 2014 1:40
I really like the way these tag helpers are looking. I really think the example of the "User.Identity.IsAuthenticated" section of the code you show above. Looking that before and after is such a great way to see how much better some things will be with TagHelpers.

I do think it would be helpful to have a prefix, I lean towards "@" prefix, it just kinda feels right. From my experiences with angular it is nice to know to start with "ng-". I also think the desaturation and/or italics are a good idea to separate the code from the client side html.
December 03, 2014 18:55
The thing about the attribute-based mapping to a strongly-typed controller and index feels like using magic strings.

I vote for adopting the Fubu HtmlTags library: http://htmltags.fubu-project.org/

It leverages the best of a strongly-typed language with configurable conventions and instead of returning a plain string (primitive obsession) it returns a rich HtmlTag type with a fluent API that reads like jQuery, something with wich a lot of front-end devs are now familiar.
December 04, 2014 13:44
Some differentiation with standard HTML attributes is mandatory, for me... by the way, some HTML elements already implement the "action" attribute ("form", which is also a potential target for the "action" TagHelper).

Color coding in the editor is nice, but it's not enough. I think prefixes or namespaces should be used. Namespaces are maybe too much, because they involve changing the page root/declarations, and views are usually coded on conventions.

"asp-" prefix are fine for me.
December 07, 2014 1:58
What about :

< a .controller="Home" .action="Index">

Shows quite nicely in my unbiased opinion ;-) that this is a tag helper member rather than an html attribute.
December 08, 2014 5:32
I'll go with those suggesting something like < li>< a href="@Home.Index()">Home< /a>< /li> or something as close as possible, without introducing non-standard markup)
December 10, 2014 17:53
I think designers are going to have a difficult time telling the difference between standard HTML tags and TagHelpers. In most cases the TagHelper markup is completely replaced at runtime, if a designer is really going to have to understand the relationship with TagHelpers and how they are processed. In my opinion razor is easier to spot, you can't miss the "@".

Would it make more sense to add attributes in a single property?

< a server="{Controller: "Home, Action: "Index"}">Home< /a>
December 12, 2014 16:25
This is a terrible idea! Webforms all over again! Don't do it!
It's already hard to read HTML and guess what will be left in the client, this will make it much, much worse. Don't do it!
December 12, 2014 18:13
I don't think I will use them, I don't want server code and client code to be lost within each other.
What I would like is for HtmlHelpers be Strongly typed, I like not to be able to enter the wrong code, and at least be notified if it is wrong.
December 12, 2014 20:09
What happend to the @helper in ASP.NET MVC 6?

I love the @helper in MVC. The only thing i hate is, the requirement to put the .cshtml/.vbhtml file in the App_Code folder. I would love it, if i could add that files any where. (e.g. /Views/Helpers/MyHelper.cshtml).

Any new about that? Shouldn't be impossible with Roslyn now...
December 13, 2014 21:21
100% agree with Daniel Mettler
please don't make a mess again like webforms
keep MVC neat & clean please
December 15, 2014 23:50
From the language syntax point of view, this is going to be horrible and ambiguous for human readability. A razor view is composed of mark-up (static) and active code (dynamic) portions. In the existing razor syntax there is extremely clean boundary to distinguish between those. '@' to transition from mark-up to active code and an element syntax for vice versa. The new proposed syntax is absolutely a mark up syntax giving the reader the 'correct' impression that this is a static content that is going to render as is. For God Sake please do not spoil this beautiful syntactic isolation with this new mess, if you were lucky enough to produce a nice thing 'incidentally' once in the blue moon.
December 15, 2014 23:57
This is only going to lengthen the learning curve. Let one syntax have one and only one interpretation <> is for static content, please leave it to mean only static content.
December 18, 2014 22:02
My gut reaction is "yuck." I tend to agree with what others have said: it feels like ASP.NET vNext is MS chasing what other frameworks are doing. But you're forgetting about the strengths of *this* platform. I hope that changes.

If you are going to make changes to how Razor views are generated, it needs to be something that is strongly-typed. The helpers from MVC Futures were closer than these string-based solutions. Let me repeat that: Razor needs *fewer* strings, not more.

C# is statically typed. Let's use that to our advantage.
December 22, 2014 1:56
Please don't bring us back to Web Forms again! This approach obscures HTML with server-side technology specifics and will likely lead to confusion among less skilled developers.

In my opinion, a key point about writing great HTML is understanding exactly what your markup does. Filling up a bunch of magic attributes in the view is a step in the opposite direction.

As an alternative, I would propose simplifying HTML helpers. Generating HTML in them is a bit awkward because of mixing method code with markup.

How about introducing a concept of "HTML templates with placeholders", where you'd (1) put all the HTML you want, (2) sprinkle the necessary placeholders here and there, then (3) call that from an HTML helper? Something along the line of T4. This would keep concerns cleanly separated.
December 22, 2014 2:28
Another vote for: PLEASE PLEASE, no more magic strings. Find a way to build T4MVC-like functionality into the framework.

Another vote for: Skip the TagHelper and just use something like Fubu HtmlTags to make HtmlHelpers better, rather than try to make everything look like HTML.

Another vote for: If you must do TagHelpers, yes, please use a prefix. I agree that "@" would be nice if you can make it work.
December 31, 2014 8:49
Thank you for sharing excellent informations. Your website is very cool. I am impressed by the details that you have on this blog. It reveals how nicely you understand this subject. Bookmarked this website page, will come back for more articles. You, my pal, ROCK! I found just the info I already searched everywhere and just could not come across. What a perfect site.
February 06, 2015 9:52
It's going to be ending off mine day, but before end I am reading this impressive piece of writing to increase my
know-how.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.