Page 68 - MSDN Magazine, November 2017
P. 68
WithRazor,theASP.NETteamalsointroducedanartifactknown as HTML helpers. An HTML helper is a sort of small HTML factory that gets some input data and emits just the HTML you want. However, HTML helpers never won over developers, so in ASP.NET Core a much better tool has been added: tag helpers. Tag helpers play the same role as HTML helpers—they work as HTML factories—but provide a much more concise and natural syntax. In particular, you don’t need any C# code to tie tag helpers with the Razor template code. Instead, they look like elements of an extended HTML syntax. Here’s an example of a tag helper:
<environment names="Development">
<script src="~/content/scripts/yourapp.dev.js" />
</environment>
<environment names="Staging, Production">
<script src="~/content/scripts/yourapp.min.js" asp-append-version="true" />
</environment>
The environment markup element isn’t emitted verbatim to the browser. Instead, its entire subtree is parsed server-side by a tag helper component that’s able to read attributes, and inspect and modify the current HTML tree. In this example, the tag helper responsible for the environment element matches the current ASP.NET Core environment to the content of the names attribute, and emits only the script elements that apply. In addition, the script element is processed by another tag helper that inspects the tree looking for an asp-append-version custom attribute. If found, the actual URL being generated is appended with a timestamp to ensure that the linked resource is never cached.
Tag helpers are C# classes inherited conventionally from a base class or declaratively bound to markup elements and attributes. Each Razor file that intends to use tag helpers must declare them using the @addTagHelper directive. The directive simply registers tag helper classes from a given .NET Core assembly. The @addTagHelper direc- tive may appear in individual Razor files but more commonly goes in the _ViewImports.cshtml file and applies globally to all views:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Tag helpers are a cool piece of technology, but they represent a trade-off between expressivity and cost of server-side rendering.
Attributes and elements recognized as tag helpers are also emphasized in Visual Studio with a special color. ASP.NET Core comes with a full bag of predefined tag helpers that can be grouped in a few categories. Some affect particular HTML elements you can have in a Razor template, such as form, input, textarea, label and select. Some helpers instead exist to simplify and automate the display of validation messages within forms. All predefined tag helpers share the asp-* name prefix. More information can be found at bit.ly/2w3BSS2.
Tag helpers help keep the Razor source code quite readable and concise. In light of this, there would be no reason to avoid using
helpers.Overall,Iwouldrecommendusingtaghelperstoauto- mate the writing of long, repetitive blocks of markup code, rather than creating anything like a view-specific language. The more you use tag helpers, in fact, the more you drive yourself away from plain HTML and the more expensive you make the rendering of HTML views. Tag helpers are a cool piece of technology, but they represent a trade-off between expressivity and cost of server-side rendering. Speaking of benefits, it’s also worth mentioning that tag helpers don’t alter the overall markup syntax so you can easily open a Razor file with tag helpers in any HTML editor without incur- ring parsing issues. The same is hardly true with HTML helpers.
View Components
Technically speaking, view components are self-contained com- ponents that include both logic and view. In ASP.NET Core, they replace child actions, which were available in classic ASP.NET MVC 5. You reference views components in Razor files via a C# block and pass them any input data that’s required:
@await Component.InvokeAsync("LatestNews", new { count = 4 })
Internally, the view component will run its own logic, process the data you passed in and return a view ready for rendering. There are no predefined view components in ASP.NET Core, meaning that they’ll be created on a strict application basis. The previous line of code presents a LatestNews view component that’s a pack- aged block of markup conceptually similar to partial views. The difference between a partial view and a view component is in the internal implementation. A partial view is a plain Razor template that optionally receives input data and incorporates that in the HTML template of which it’s made. A partial view isn’t expected to have any behavior of its own except for formatting and rendering.
A view component is a more sophisticated form of a partial view. A view component optionally receives plain input parameters that it typically uses to retrieve and process its data. Once available, data is incorporated in an embedded Razor template, much the way a partial view behaves. However, a view component is faster in implementa- tion because it doesn’t go through the controller pipeline the way child actions do. This means there’s no model binding and no action filters.
Overall, view components serve the noble purpose of helping to componentize the view so that it results from the composition of distinct and self-made widgets. This point is a double-edged sword. Having the view split into distinct and independent components seems a convenient way to organize the work and possibly make it more parallel by having different developers take care of the various parts. However, view components don’t speed up things in all cases. It all depends on what each component does internally. When discussing view components, and the Composi- tion UI pattern underneath its vision, you’re often presented with the architecture of large service-oriented systems as an example, and that’s absolutely correct.
However, when you blindly use view components, and the pattern, in the context of a monolithic, compact system, you might end up with poorly optimized query logic. Each component might query for its data, producing repeat queries and unnecessary database traffic. View components can be employed in this scenario, but you should consider caching layers to avoid bad outcomes.
64 msdn magazine
Cutting Edge