Crear asistentes de etiquetas en ASP.NET Core
Por Rick Anderson
Vea o descargue el código de ejemplo (cómo descargarlo)
Introducción a los asistentes de etiquetas
En este tutorial se proporciona una introducción a la programación de asistentes de etiquetas. En Introducción a los asistentes de etiquetas se describen las ventajas que proporcionan los asistentes de etiquetas.
Un asistente de etiquetas es una clase que implementa la interfaz ITagHelper
. A pesar de ello, cuando se crea un asistente de etiquetas, normalmente se deriva de TagHelper
, lo que da acceso al método Process
.
Cree un proyecto de ASP.NET Core denominado AuthoringTagHelpers. No necesita autenticación para este proyecto.
Cree una carpeta para almacenar los asistentes de etiquetas denominada TagHelpers. La carpeta TagHelpersno es necesaria, pero es una convención razonable. Ahora vamos a empezar a escribir algunos asistentes de etiquetas simples.
Asistente de etiquetas mínima
En esta sección, escribirá un asistente de etiquetas que actualice una etiqueta de correo electrónico. Por ejemplo:
<email>Support</email>
El servidor usará nuestro asistente de etiquetas de correo electrónico para convertir ese marcado en lo siguiente:
<a href="mailto:Support@contoso.com">Support@contoso.com</a>
Es decir, una etiqueta delimitadora lo convierte en un vínculo de correo electrónico. Tal vez le interese si está escribiendo un motor de blogs y necesita que envíe correos electrónicos a contactos de marketing, soporte técnico y de otro tipo, todos ellos en el mismo dominio.
Agregue la siguiente clase
EmailTagHelper
a la carpeta TagHelpers.using Microsoft.AspNetCore.Razor.TagHelpers; using System.Threading.Tasks; namespace AuthoringTagHelpers.TagHelpers { public class EmailTagHelper : TagHelper { public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; // Replaces <email> with <a> tag } } }
Los asistentes de etiquetas usan una convención de nomenclatura que tiene como destino los elementos de la clase raíz (menos la parte TagHelper del nombre de clase). En este ejemplo, el nombre raíz de EmailTagHelper es email, por lo que el destino será la etiqueta
<email>
. Esta convención de nomenclatura debería funcionar para la mayoría de los asistentes de etiquetas. Más adelante veremos cómo invalidarla.La clase
EmailTagHelper
deriva deTagHelper
. La claseTagHelper
proporciona métodos y propiedades para escribir asistentes de etiquetas.El método
Process
invalidado controla lo que hace el asistente de etiquetas cuando se ejecuta. La claseTagHelper
también proporciona una versión asincrónica (ProcessAsync
) con los mismos parámetros.El parámetro de contexto para
Process
(yProcessAsync
) contiene información relacionada con la ejecución de la etiqueta HTML actual.El parámetro de salida para
Process
(yProcessAsync
) contiene un elemento HTML con estado que representa el origen original usado para generar una etiqueta y contenido HTML.El nombre de nuestra clase tiene un sufijo TagHelper, que no es necesario, pero es una convención recomendada. Podría declarar la clase de la manera siguiente:
public class Email : TagHelper
Para hacer que la clase
EmailTagHelper
esté disponible para todas nuestras vistas de Razor, agregue la directivaaddTagHelper
al archivoViews/_ViewImports.cshtml
:@using AuthoringTagHelpers @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, AuthoringTagHelpers
El código anterior usa la sintaxis de comodines para especificar que todos los asistentes de etiquetas del ensamblado estarán disponibles. La primera cadena después de
@addTagHelper
especifica el asistente de etiquetas que se va a cargar (use "*" para todos los asistentes de etiquetas), mientras que la segunda cadena "AuthoringTagHelpers" especifica el ensamblado en el que se encuentra el asistente de etiquetas. Además, tenga en cuenta que la segunda línea incorpora los asistentes de etiquetas de ASP.NET Core MVC mediante la sintaxis de comodines (esos asistentes se tratan en el tema Introducción a los asistentes de etiquetas). La directiva@addTagHelper
hace que el asistente de etiquetas esté disponible en la vista Razor. Como alternativa, puede proporcionar el nombre completo (FQN) de un asistente de etiquetas como se muestra a continuación:
@using AuthoringTagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper AuthoringTagHelpers.TagHelpers.EmailTagHelper, AuthoringTagHelpers
Para agregar un asistente de etiquetas a una vista con un FQN, agregue primero el FQN (AuthoringTagHelpers.TagHelpers.EmailTagHelper
) y, después, el nombre del ensamblado (AuthoringTagHelpers, no necesariamente namespace
). La mayoría de los desarrolladores prefiere usar la sintaxis de comodines. En Introducción a los asistentes de etiquetas se describe en detalle la adición y eliminación de asistentes de etiquetas, la jerarquía y la sintaxis de comodines.
Actualización del marcado en el archivo
Views/Home/Contact.cshtml
con estos cambios:@{ ViewData["Title"] = "Contact"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <address> One Microsoft Way<br /> Redmond, WA 98052<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address> <address> <strong>Support:</strong><email>Support</email><br /> <strong>Marketing:</strong><email>Marketing</email> </address>
Ejecute la aplicación y use su explorador favorito para ver el código fuente HTML, a fin de comprobar que las etiquetas de correo electrónico se han reemplazado por un marcado delimitador (por ejemplo,
<a>Support</a>
). Support y Marketing se representan como vínculos, pero no tienen un atributohref
que los haga funcionales. Esto lo corregiremos en la sección siguiente.
SetAttribute y SetContent
En esta sección, actualizaremos EmailTagHelper
para que cree una etiqueta delimitadora válida para correo electrónico. Lo actualizaremos para que tome información de una vista de Razor(en forma de atributo mail-to
) y la use al generar el delimitador.
Actualice la clase EmailTagHelper
con lo siguiente:
public class EmailTagHelper : TagHelper
{
private const string EmailDomain = "contoso.com";
// Can be passed via <email mail-to="..." />.
// PascalCase gets translated into kebab-case.
public string MailTo { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "a"; // Replaces <email> with <a> tag
var address = MailTo + "@" + EmailDomain;
output.Attributes.SetAttribute("href", "mailto:" + address);
output.Content.SetContent(address);
}
}
Los nombres de clase y propiedad con grafía Pascal para los asistentes de etiquetas se convierten a su grafía kebab. Por tanto, para usar el atributo
MailTo
, usará su equivalente<email mail-to="value"/>
.La última línea establece el contenido completado para nuestro asistente de etiquetas mínimamente funcional.
La línea resaltada muestra la sintaxis para agregar atributos:
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "a"; // Replaces <email> with <a> tag
var address = MailTo + "@" + EmailDomain;
output.Attributes.SetAttribute("href", "mailto:" + address);
output.Content.SetContent(address);
}
Este enfoque funciona para el atributo "href" siempre y cuando no exista actualmente en la colección de atributos. También puede usar el método output.Attributes.Add
para agregar un atributo del asistente de etiquetas al final de la colección de atributos de etiqueta.
Actualización del marcado en el archivo
Views/Home/Contact.cshtml
con estos cambios:@{ ViewData["Title"] = "Contact Copy"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <address> One Microsoft Way Copy Version <br /> Redmond, WA 98052-6399<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address> <address> <strong>Support:</strong><email mail-to="Support"></email><br /> <strong>Marketing:</strong><email mail-to="Marketing"></email> </address>
Ejecute la aplicación y compruebe que genera los vínculos correctos.
Nota:
Si escribe la etiqueta de correo electrónico como de autocierre (<email mail-to="Rick" />
), la salida final también será de autocierre. Para habilitar la capacidad de escribir la etiqueta únicamente con una etiqueta de apertura (<email mail-to="Rick">
), debe marcar la clase con lo siguiente:
[HtmlTargetElement("email", TagStructure = TagStructure.WithoutEndTag)]
public class EmailVoidTagHelper : TagHelper
{
private const string EmailDomain = "contoso.com";
// Code removed for brevity
Con un asistente de etiquetas de correo electrónico de autocierre, el resultado sería <a href="mailto:Rick@contoso.com" />
. Las etiquetas delimitadoras de autocierre no son HTML válido, por lo que no le interesa crear una, pero tal vez le convenga crear un asistente de etiquetas de autocierre. Los asistentes de etiquetas establecen el tipo de la propiedad TagMode
después de leer una etiqueta.
También puede asignar un nombre de atributo diferente a una propiedad mediante el atributo [HtmlAttributeName]
.
Para asignar un atributo denominado recipient
a la propiedad MailTo
:
[HtmlAttributeName("recipient")]
public string? MailTo { get; set; }
Asistente de etiquetas para el atributo recipient
:
<email recipient="…"/>
ProcessAsync
En esta sección, escribiremos un asistente de correo electrónico asincrónico.
Reemplace la clase
EmailTagHelper
por el siguiente código:public class EmailTagHelper : TagHelper { private const string EmailDomain = "contoso.com"; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; // Replaces <email> with <a> tag var content = await output.GetChildContentAsync(); var target = content.GetContent() + "@" + EmailDomain; output.Attributes.SetAttribute("href", "mailto:" + target); output.Content.SetContent(target); } }
Notas:
Esta versión usa el método
ProcessAsync
asincrónico. El métodoGetChildContentAsync
asincrónico devuelve un valorTask
que contieneTagHelperContent
.Use el parámetro
output
para obtener el contenido del elemento HTML.
Realice el cambio siguiente en el archivo
Views/Home/Contact.cshtml
para que el asistente de etiquetas pueda obtener el correo electrónico de destino.@{ ViewData["Title"] = "Contact"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <address> One Microsoft Way<br /> Redmond, WA 98052<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address> <address> <strong>Support:</strong><email>Support</email><br /> <strong>Marketing:</strong><email>Marketing</email> </address>
Ejecute la aplicación y compruebe que genera vínculos de correo electrónico válidos.
RemoveAll, PreContent.SetHtmlContent y PostContent.SetHtmlContent
Agregue la siguiente clase
BoldTagHelper
a la carpeta TagHelpers.using Microsoft.AspNetCore.Razor.TagHelpers; namespace AuthoringTagHelpers.TagHelpers { [HtmlTargetElement(Attributes = "bold")] public class BoldTagHelper : TagHelper { public override void Process(TagHelperContext context, TagHelperOutput output) { output.Attributes.RemoveAll("bold"); output.PreContent.SetHtmlContent("<strong>"); output.PostContent.SetHtmlContent("</strong>"); } } }
El atributo
[HtmlTargetElement]
pasa un parámetro de atributo que especifica que todos los elementos HTML que contengan un atributo HTML denominado "bold" coincidirán, y se ejecutará el método de invalidaciónProcess
de la clase. En nuestro ejemplo, el métodoProcess
quita el atributo "bold" y rodea el marcado contenedor con<strong></strong>
.Dado que no le interesa reemplazar el contenido existente de la etiqueta, debe escribir la etiqueta de apertura
<strong>
con el métodoPreContent.SetHtmlContent
y la etiqueta de cierre</strong>
con el métodoPostContent.SetHtmlContent
.
Modifique la vista
About.cshtml
para que contenga un valor de atributobold
. A continuación se muestra el código completado.@{ ViewData["Title"] = "About"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <p bold>Use this area to provide additional information.</p> <bold> Is this bold?</bold>
Ejecutar la aplicación. Puede usar el explorador que prefiera para inspeccionar el origen y comprobar el marcado.
El atributo
[HtmlTargetElement]
anterior solo tiene como destino el marcado HTML que proporciona el nombre de atributo "bold". El asistente de etiquetas no ha modificado el elemento<bold>
.Convierta en comentario la línea de atributo
[HtmlTargetElement]
y de forma predeterminada tendrá como destino las etiquetas<bold>
, es decir, el marcado HTML con formato<bold>
. Recuerde que la convención de nomenclatura predeterminada hará coincidir el nombre de clase BoldTagHelper con las etiquetas<bold>
.Ejecute la aplicación y compruebe que el asistente de etiquetas procesa la etiqueta
<bold>
.
El proceso de decorar una clase con varios atributos [HtmlTargetElement]
tiene como resultado una operación OR lógica de los destinos. Por ejemplo, si se usa el código siguiente, una etiqueta bold o un atributo bold coincidirán.
[HtmlTargetElement("bold")]
[HtmlTargetElement(Attributes = "bold")]
public class BoldTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.RemoveAll("bold");
output.PreContent.SetHtmlContent("<strong>");
output.PostContent.SetHtmlContent("</strong>");
}
}
Cuando se agregan varios atributos a la misma instrucción, el tiempo de ejecución los trata como una operación AND lógica. Por ejemplo, en el código siguiente, un elemento HTML debe denominarse "bold" con un atributo denominado "bold" (<bold bold />
) para que coincida.
[HtmlTargetElement("bold", Attributes = "bold")]
También puede usar [HtmlTargetElement]
para cambiar el nombre del elemento de destino. Por ejemplo, si quiere que BoldTagHelper
tenga como destino etiquetas <MyBold>
, use el atributo siguiente:
[HtmlTargetElement("MyBold")]
Pasar un modelo a un asistente de etiquetas
Agregue una carpeta Models.
Agregue la clase
WebsiteContext
siguiente a la carpeta Models:using System; namespace AuthoringTagHelpers.Models { public class WebsiteContext { public Version Version { get; set; } public int CopyrightYear { get; set; } public bool Approved { get; set; } public int TagsToShow { get; set; } } }
Agregue la siguiente clase
WebsiteInformationTagHelper
a la carpeta TagHelpers.using System; using AuthoringTagHelpers.Models; using Microsoft.AspNetCore.Razor.TagHelpers; namespace AuthoringTagHelpers.TagHelpers { public class WebsiteInformationTagHelper : TagHelper { public WebsiteContext Info { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "section"; output.Content.SetHtmlContent( $@"<ul><li><strong>Version:</strong> {Info.Version}</li> <li><strong>Copyright Year:</strong> {Info.CopyrightYear}</li> <li><strong>Approved:</strong> {Info.Approved}</li> <li><strong>Number of tags to show:</strong> {Info.TagsToShow}</li></ul>"); output.TagMode = TagMode.StartTagAndEndTag; } } }
Como se ha indicado anteriormente, los asistentes de etiquetas convierten las propiedades y nombres de clase de C# con grafía Pascal para asistentes de etiquetas en grafía kebab. Por tanto, para usar
WebsiteInformationTagHelper
en Razor, deberá escribir<website-information />
.No está identificando de manera explícita el elemento de destino con el atributo
[HtmlTargetElement]
, por lo que el destino será el valor predeterminado dewebsite-information
. Si ha aplicado el atributo siguiente (tenga en cuenta que no tiene grafía kebab, pero coincide con el nombre de clase):
[HtmlTargetElement("WebsiteInformation")]
La etiqueta con grafía kebab
<website-information />
no coincidiría. Si quiere usar el atributo[HtmlTargetElement]
, debe usar la grafía kebab como se muestra a continuación:[HtmlTargetElement("Website-Information")]
Los elementos que son de autocierre no tienen contenido. En este ejemplo, el marcado de Razor usará una etiqueta de autocierre, pero el asistente de etiquetas creará un elemento section (que no es de autocierre, y el contenido se escribirá dentro del elemento
section
). Por tanto, debe establecerTagMode
enStartTagAndEndTag
para escribir la salida. Como alternativa, puede convertir en comentario la línea donde se estableceTagMode
y escribir marcado con una etiqueta de cierre. (Más adelante en este tutorial se proporciona marcado de ejemplo).El signo de dólar
$
de la línea siguiente usa una cadena interpolada:
$@"<ul><li><strong>Version:</strong> {Info.Version}</li>
Agregue el marcado siguiente en la vista
About.cshtml
. En el marcado resaltado se muestra la información del sitio web.@using AuthoringTagHelpers.Models @{ ViewData["Title"] = "About"; WebsiteContext webContext = new WebsiteContext { Version = new Version(1, 3), CopyrightYear = 1638, Approved = true, TagsToShow = 131 }; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <p bold>Use this area to provide additional information.</p> <bold> Is this bold?</bold> <h3> web site info </h3> <website-information info="webContext" />
Nota:
En el marcado de Razor que se muestra a continuación:
<website-information info="webContext" />
Razor sabe que el atributo
info
es una clase, no una cadena, y usted quiere escribir código de C#. Todos los atributos de asistentes de etiquetas que no sean una cadena deben escribirse sin el carácter@
.Ejecute la aplicación y vaya a la vista About para ver la información del sitio web.
Nota:
Puede usar el marcado siguiente con una etiqueta de cierre y quitar la línea con
TagMode.StartTagAndEndTag
del asistente de etiquetas:<website-information info="webContext" > </website-information>
Asistente de etiquetas de condición
El asistente de etiquetas de condición representa la salida cuando se pasa un valor true.
Agregue la siguiente clase
ConditionTagHelper
a la carpeta TagHelpers.using Microsoft.AspNetCore.Razor.TagHelpers; namespace AuthoringTagHelpers.TagHelpers { [HtmlTargetElement(Attributes = nameof(Condition))] public class ConditionTagHelper : TagHelper { public bool Condition { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { if (!Condition) { output.SuppressOutput(); } } } }
Reemplace el contenido del archivo
Views/Home/Index.cshtml
con el siguiente marcado:@using AuthoringTagHelpers.Models @model WebsiteContext @{ ViewData["Title"] = "Home Page"; } <div> <h3>Information about our website (outdated):</h3> <Website-InforMation info="Model" /> <div condition="Model.Approved"> <p> This website has <strong surround="em">@Model.Approved</strong> been approved yet. Visit www.contoso.com for more information. </p> </div> </div>
Reemplace el método
Index
del controladorHome
por el código siguiente:public IActionResult Index(bool approved = false) { return View(new WebsiteContext { Approved = approved, CopyrightYear = 2015, Version = new Version(1, 3, 3, 7), TagsToShow = 20 }); }
Ejecuta la aplicación y ve a la página home. El marcado del elemento condicional
div
no se representará. Anexe la cadena de consulta?approved=true
a la dirección URL (por ejemplo,http://localhost:1235/Home/Index?approved=true
).approved
se establece en true y se muestra el marcado condicional.
Nota
Use el operador nameof para especificar el atributo de destino en lugar de especificar una cadena, como hizo con el asistente de etiquetas bold:
[HtmlTargetElement(Attributes = nameof(Condition))]
// [HtmlTargetElement(Attributes = "condition")]
public class ConditionTagHelper : TagHelper
{
public bool Condition { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!Condition)
{
output.SuppressOutput();
}
}
}
El operador nameof protegerá el código si en algún momento debe refactorizarse (tal vez interese cambiar el nombre a RedCondition
).
Evitar conflictos de asistentes de etiquetas
En esta sección, escribirá un par de asistentes de etiquetas de vinculación automática. La primera reemplazará el marcado que contiene una dirección URL que empieza con HTTP por una etiqueta delimitadora HTML que contiene la misma dirección URL (y, por tanto, produce un vínculo a la dirección URL). La segunda hará lo mismo para una dirección URL que empieza con WWW.
Dado que estos dos asistentes están estrechamente relacionados y tal vez las refactorice en el futuro, los guardaremos en el mismo archivo.
Agregue la siguiente clase
AutoLinkerHttpTagHelper
a la carpeta TagHelpers.[HtmlTargetElement("p")] public class AutoLinkerHttpTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent.GetContent(), @"\b(?:https?://)(\S+)\b", "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version} } }
Nota
La clase
AutoLinkerHttpTagHelper
tiene como destino elementosp
y usa Regex para crear el delimitador.Agregue el marcado siguiente al final del archivo
Views/Home/Contact.cshtml
:@{ ViewData["Title"] = "Contact"; } <h2>@ViewData["Title"].</h2> <h3>@ViewData["Message"]</h3> <address> One Microsoft Way<br /> Redmond, WA 98052<br /> <abbr title="Phone">P:</abbr> 425.555.0100 </address> <address> <strong>Support:</strong><email>Support</email><br /> <strong>Marketing:</strong><email>Marketing</email> </address> <p>Visit us at http://docs.asp.net or at www.microsoft.com</p>
Ejecute la aplicación y compruebe que el asistente de etiquetas representa el delimitador correctamente.
Actualice la clase
AutoLinker
para que incluya la aplicación auxiliar de etiquetasAutoLinkerWwwTagHelper
que convertirá el texto www en una etiqueta delimitadora que también contenga el texto www original. El código actualizado aparece resaltado a continuación:[HtmlTargetElement("p")] public class AutoLinkerHttpTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent.GetContent(), @"\b(?:https?://)(\S+)\b", "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version} } } [HtmlTargetElement("p")] public class AutoLinkerWwwTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent.GetContent(), @"\b(www\.)(\S+)\b", "<a target=\"_blank\" href=\"http://$0\">$0</a>")); // www version } } }
Ejecutar la aplicación. Observe que el texto www se representa como un vínculo, a diferencia del texto HTTP. Si coloca un punto de interrupción en ambas clases, verá que la clase del asistente de etiquetas HTTP se ejecuta primero. El problema es que la salida del asistente de etiquetas se almacena en caché y, cuando se ejecuta el asistente de etiquetas WWW, sobrescribe la salida almacenada en caché desdel asistente de etiquetas HTTP. Más adelante en el tutorial veremos cómo se controla el orden en el que se ejecutan los asistentes de etiquetas. Corregiremos el código con lo siguiente:
public class AutoLinkerHttpTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent, @"\b(?:https?://)(\S+)\b", "<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version} } } [HtmlTargetElement("p")] public class AutoLinkerWwwTagHelper : TagHelper { public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent(); // Find Urls in the content and replace them with their anchor tag equivalent. output.Content.SetHtmlContent(Regex.Replace( childContent, @"\b(www\.)(\S+)\b", "<a target=\"_blank\" href=\"http://$0\">$0</a>")); // www version } }
Nota:
La primera vez que editó los asistentes de etiquetas de vinculación automática, obtuvo el contenido del destino con el código siguiente:
var childContent = await output.GetChildContentAsync();
Es decir, ha llamado a
GetChildContentAsync
mediante la salidaTagHelperOutput
pasada al métodoProcessAsync
. Como ya se ha indicado, como la salida se almacena en caché, prevalece el último asistente de etiquetas que se ejecuta. Para corregir el error, ha usado el código siguiente:var childContent = output.Content.IsModified ? output.Content.GetContent() : (await output.GetChildContentAsync()).GetContent();
El código anterior comprueba si se ha modificado el contenido y, en caso afirmativo, obtiene el contenido del búfer de salida.
Ejecute la aplicación y compruebe que los dos vínculos funcionan según lo previsto. Aunque podría parecer que nuestro asistente de etiquetas de vinculación automática es correcta y está completa, tiene un pequeño problema. Si el asistente de etiquetas WWW se ejecuta en primer lugar, los vínculos www no serán correctos. Actualice el código mediante la adición de la sobrecarga
Order
para controlar el orden en el que se ejecuta la etiqueta. La propiedadOrder
determina el orden de ejecución en relación con los demás asistentes de etiquetas que tienen como destino el mismo elemento. El valor de orden predeterminado es cero, y se ejecutan en primer lugar las instancias con los valores más bajos.public class AutoLinkerHttpTagHelper : TagHelper { // This filter must run before the AutoLinkerWwwTagHelper as it searches and replaces http and // the AutoLinkerWwwTagHelper adds http to the markup. public override int Order { get { return int.MinValue; } }
El código anterior garantizará que el asistente de etiquetas HTTP se ejecuta antes que el asistente de etiquetas WWW. Cambie
Order
aMaxValue
y compruebe que el marcado generado para la etiqueta WWW es incorrecto.
Inspeccionar y recuperar contenido secundario
Los asistentes de etiquetas proporcionan varias propiedades para recuperar contenido.
- El resultado de
GetChildContentAsync
se pueden anexar aoutput.Content
. - Puede inspeccionar el resultado de
GetChildContentAsync
conGetContent
. - Si modifica
output.Content
, el cuerpo de TagHelper no se ejecutará ni representará a menos que llame aGetChildContentAsync
, como en nuestro ejemplo de vinculación automática:
public class AutoLinkerHttpTagHelper : TagHelper
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var childContent = output.Content.IsModified ? output.Content.GetContent() :
(await output.GetChildContentAsync()).GetContent();
// Find Urls in the content and replace them with their anchor tag equivalent.
output.Content.SetHtmlContent(Regex.Replace(
childContent,
@"\b(?:https?://)(\S+)\b",
"<a target=\"_blank\" href=\"$0\">$0</a>")); // http link version}
}
}
- Varias llamadas a
GetChildContentAsync
devuelven el mismo valor y no vuelven a ejecutar el cuerpo deTagHelper
a menos que se pase un parámetro false que indique que no se use el resultado almacenado en caché.
Carga de la vista parcial minimizada TagHelper
En entornos de producción, se puede mejorar el rendimiento cargando vistas parciales minimizadas. Para aprovechar las ventajas de la vista parcial minimizada en producción, siga estos pasos:
- Cree o configure un proceso de compilación anterior que minimice las vistas parciales.
- Utilice el siguiente código para cargar las vistas parciales minimizadas en entornos que no son de desarrollo.
public class MinifiedVersionPartialTagHelper : PartialTagHelper
{
public MinifiedVersionPartialTagHelper(ICompositeViewEngine viewEngine,
IViewBufferScope viewBufferScope)
: base(viewEngine, viewBufferScope)
{
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
// Append ".min" to load the minified partial view.
if (!IsDevelopment())
{
Name += ".min";
}
return base.ProcessAsync(context, output);
}
private bool IsDevelopment()
{
return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")
== EnvironmentName.Development;
}
}