Генерация html asp net

Каскадная генерация HTML-тегов посредством C#

В очередном процессе написания веб приложения под ASP.NET MVC с использованием Bootstrap поймал себя на мысли, что неизбежное создание HTML-тэгов можно было бы и подсократить. Речь пойдёт не о наборе пользовательских элементов управления для расширения пространства Html.*, а о том, что лежит немножечко глЫбже. Для торопыг предлагаю глянуть сюда (GitHub), а для остальных добро пожаловать под кат.

Задача

Имеется HTML-тэг, содержащий в себе название, классы, стили, атрибуты и т.д. В .NET для «ручного» создания сей красоты предполагается использование класса TagBuilder и постепенное его заполнение нужными мета и просто данными.

Регулярное использование этого класса показалось мне слишком муторным. Постоянные *.AddCssClass, *.Attributes.Add, *.MergeAttribute и *.ToString(TagRenderMode.SelfClosing) — в какой-то момент начинают раздражать своей пошаговостью.

Вот к примеру, как выглядит стандартного элемента-кнопки:

// C# var tb = new TagBuilder("button"); tb.Attributes.Add("type", "button"); tb.AddCssClass("btn"); tb.AddCssClass("btn-success"); tb.SetInnerText("Success"); var htmlString = tb.ToString(TagRenderMode.Normal);

Добавим сюда то, что порой HTML-тэги требуют вложенности, а значит требуется наличие одного или многих *.InnerHtml с параметром, каждый из которых в свою очередь должен создаваться точно так же — длинно-размеренно-пошагово — то становится понятно, что хочется чего-то менее рутинного.

Вот так и родился класс TagDecorator.

Сформулированная задача которую хотелось бы решить звучит следующим образом — упростить создание HTML-тэгов, отойти от пошаговости и организовать естественную вложенность иерархии HTML.

Решение

На начальном этапе решение состояло из двух классов, но к ним впоследствии добавился ещё один:

TagDecorator — основной работающий класс, который ответственнен за превращение обычного текста в класс, представляющий тэг (TagWrapper), к которому могут прицепляться дополнительные extensions. В существующем примере есть как общие функции AddAttribute, AddCss, так и частные функции AddType, AddName, AddId — создающие конкретные атрибуты.

TagWrapper — класс, представляющий тэг. Был создан, чтобы по возможности полностью отойти от TagBuilder и новые extensions в IntelliSense не путались со свойствами класса TagBuilder.

Tags — класс, необходимый для разделения begin/end tags, чтобы сделать возможной реализацию обрамляющих блоков HTML, использующихся в RazorView

Примеры

На указанном примере кнопки преимущества результата применения TagDecorator несколько неочевидны:

var htmlString = "button".ToTag() .AddType("button") .AddCss(new[] ) .SetText("Success") .ToString(); 

Но вот уже на примере Bootstrap card — всё уже становится намного приятней глазу:

var divMain = new TagBuilder("div"); divMain.AddCssClass("card"); divMain.Attributes.Add("style", "width: 18rem;"); var img = new TagBuilder("img"); img.AddCssClass("card-img-top"); img.Attributes.Add("src", ". "); img.Attributes.Add("alt", "Card image cap"); var divBody = new TagBuilder("div"); divBody.AddCssClass("card-body"); var h = new TagBuilder("h5"); h.AddCssClass("card-title"); h.SetInnerText("Card title"); var p = new TagBuilder("p"); p.AddCssClass("card-text"); p.SetInnerText("Some quick example text to build on the card title and make up the bulk of the card's content."); var a = new TagBuilder("a"); a.Attributes.Add("href", "#"); a.AddCssClass("btn"); a.AddCssClass("btn-primary"); a.SetInnerText("Go somewhere"); divBody.InnerHtml += h.ToString(TagRenderMode.Normal); divBody.InnerHtml += p.ToString(TagRenderMode.Normal); divBody.InnerHtml += a.ToString(TagRenderMode.Normal); divMain.InnerHtml += img.ToString(TagRenderMode.Normal); divMain.InnerHtml += divBody.ToString(TagRenderMode.Normal); return divMain.ToString(TagRenderMode.Normal);
var htmlString = "div".ToTag() .AddCss("card") .AddAttribute("style", "width: 18rem;") .InnerHtml(new [] < "img".ToTag() .AddCss("card-img-top") .AddAttributes(new[] , new[] >), "div".ToTag() .AddCss("card-body") .InnerHtml(new [] < "h5".ToTag().AddCss("card-title").SetText("Card title"), "p".ToTag().AddCss("card-text").SetText("Some quick example text to build on the card title and make up the bulk of the card's content."), "a".ToTag().AddCss(new[] ).AddAttribute("href", "#").SetText("Go somewhere") >) >).ToString();

Результаты

Минусы

Основным из которых я считаю то, что каскадная имплементация порой сильно сдвигает код вправо, часто выводя за пределы видения разработчика, и чем сложнее иерархия — тем сильнее

Плюсы

+ Line of codes — сокращается. В простейших элементах есть выигрыш примерно 1-2 строк, в сложном HTML дереве — примерно на 1/3 по аналогии если использовать TagBuilder.

+ Наглядность — явно видно что где и какая вложенность. Всё иерархически интуитивно и проще понять.

+ Расширяемость — необходим какой-то специфический случай/атрибут — просто добавляем Extension. Необходима проверка на условие — добавляем Extension.

Возможные улучшения

Поначалу я подумывал о том, чтобы на основе данных классов создать полностью специализированные тэги, которые бы допускали бы в подсказке только определённые extensions — к примеру в тэге button убрать подсказку расширения AddReference, однако впоследствии отказался от данных планов в угоду универсальности. Но в общем и целом — данное решение теперь сильно помогает мне в моих проектах.

Предполагалось ещё создание NuGet пакета, но за недостатком времени — всё откладывается.

Источник

Генерация html asp net

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

В прошлых темах все классы компонентов представлений в качестве выходного результата использовали строку, то есть объект string. Однако такой тип для генерации результата не всегда является удобным, и как правило в качестве результата в View Component используется объект интерфейса IViewComponentResult . Имеется три встроенных класса, которые реализуют этот интерфейс:

  • ViewViewComponentResult : используется для генерации представления Razor с возможностью передачи модели. Для создания этого объекта может применяться метод View() класса ViewComponent
  • ContentViewComponentResult : применяется для отправки текстового контента. Для создания объекта используется метод Content()
  • HtmlContentViewComponentResult : представляет фрагмент кода HTML, который инкорпорируется в веб-станицу

ContentViewComponentResult

Для возврата содержимого в виде обычной строки используется объект ContentViewComponentResult . Для его создания применяется метод Content() , который в качестве параметра принимает строку.

В предыдущих темах метод Invoke компонента возвращал строку — объект string. По сути же возвращался тот же объект ContentViewComponentResult, так как фреймворк MVC автоматически преобразовывает строку в ContentViewComponentResult. Например:

using System; using Microsoft.AspNetCore.Mvc; namespace ViewComponentsApp.Components < public class Timer : ViewComponent < public IViewComponentResult Invoke() < string time = $"Текущее время: "; return Content(time); > > >

Стоит отметить, что в подобном случае необходимо наследовать класс компонента от ViewComponent, иначе мы не сможем воспользоваться методом Content.

Если эта форма определения компонента не является предпочтительной, то можно явным образом создать объект ContentViewComponentResult:

using System; using Microsoft.AspNetCore.Mvc; namespace ViewComponentsApp.Components < [ViewComponent] public class Timer < public IViewComponentResult Invoke() < string time = $"Текущее время: "; return new ContentViewComponentResult(time); > > >
 
@await Component.InvokeAsync("Timer")

мы бы увидели в браузере ту же самую строку:

IViewComponentResult в ASP.NET Core

HTML-фрагменты

Для генерации html-фрагментов, которые вставляются в основное представление, применяется класс HtmlContentViewComponentResult . Для создания html-содержимого в конструктор этого класса передается объект HtmlString с кодом html:

using System; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewComponents; namespace ViewComponentsApp.Components < [ViewComponent] public class Timer < public IViewComponentResult Invoke() < return new HtmlContentViewComponentResult( new HtmlString($"

Текущее время: ") ); > > >

В отличие от ContentViewComponentResult все html-теги будут должным образом интерпретироваться:

HtmlContentViewComponentResult в ASP.NET Core

Данный способ удобен, когда необходимо возвратить какой-то небольшой кусочек кода html для вставки на веб-страницу. Если же надо сгенерировать довольно много разметки html, то в этом случае лучше использовать ViewViewComponentResult, который будет рассмотрен в следующей теме.

Источник

Генерация html asp net

В прошлых темах все классы компонентов представлений в качестве выходного результата использовали строку, то есть объект string. Однако такой тип для генерации результата не всегда является удобным, и обычно в качестве результата в View Component используется объект интерфейса IViewComponentResult . Имеется три встроенных класса, которые реализуют этот интерфейс:

  • ViewComponentResult : используется для генерации представления Razor с возможностью передачи модели. Для создания этого объекта может применяться метод View() класса ViewComponent
  • ContentViewComponentResult : применяется для отправки текстового контента. Для создания объекта используется метод Content()
  • HtmlContentViewComponentResult : представляет фрагмент кода HTML, который инкорпорируется в веб-станицу

ContentViewComponentResult

Для возврата содержимого в виде обычной строки используется объект ContentViewComponentResult . Для его создания применяется метод Content() , который в качестве параметра принимает строку.

В предыдущих темах метод Invoke компонента возвращал строку — объект string. По сути же возвращался тот же объект ContentViewComponentResult, так как фреймворк MVC автоматически преобразовывает строку в объект типа ContentViewComponentResult. Например:

using Microsoft.AspNetCore.Mvc; namespace MvcApp.Components < public class Timer : ViewComponent < public IViewComponentResult Invoke() < string time = $"Текущее время: "; return Content(time); > > >

Стоит отметить, что в подобном случае необходимо наследовать класс компонента от ViewComponent , иначе мы не сможем воспользоваться методом Content() .

Если эта форма определения компонента не является предпочтительной, то можно явным образом создать объект ContentViewComponentResult:

using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewComponents; namespace MvcApp.Components < [ViewComponent] public class Timer < public IViewComponentResult Invoke() < string time = $"Текущее время: "; return new ContentViewComponentResult(time); > > >
 
@await Component.InvokeAsync("Timer")

мы бы увидели в браузере ту же самую строку:

Генерация контента и тип IViewComponentResult в ASP.NET Core MVC и C#

HTML-фрагменты

Для генерации html-фрагментов, которые вставляются в основное представление, применяется класс HtmlContentViewComponentResult . Для создания html-содержимого в конструктор этого класса передается объект HtmlString с кодом html:

using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewComponents; namespace MvcApp.Components < [ViewComponent] public class Timer < public IViewComponentResult Invoke() < return new HtmlContentViewComponentResult( new HtmlString($"

Текущее время: ") ); > > >

В отличие от ContentViewComponentResult все html-теги будут должным образом интерпретироваться:

View Component и HtmlContentViewComponentResult в ASP.NET Core MVC и C#

Данный способ удобен, когда необходимо возвратить какой-то небольшой кусочек кода html для вставки на веб-страницу. Если же надо сгенерировать довольно много разметки html, то в этом случае лучше использовать ViewComponentResult, который будет рассмотрен в следующей теме.

Источник

Читайте также:  Base64 for url java
Оцените статью