ASP.NET - анализировать / запрашивать HTML перед передачей и вставлять ссылки на классы CSS
Как веб-разработчик, я чувствую, что слишком много времени тратится на CSS. Я пытаюсь найти решение, в котором я могу написать повторно используемые CSS, то есть классы, и ссылаться на эти классы в HTML без дополнительного кода в файлах ASPX или ASCX и т. Д. Или файлов с выделенным кодом. Я хочу посредника, который связывает элементы HTML с классами CSS.
Чего я хочу добиться:
- Изменить HTML непосредственно перед передачей
- Выберите элементы в HTML
- На основе правил, определенных в другом месте (например, в текстовом файле, относящемся к обрабатываемой в данный момент странице):
- Добавить ссылку на класс CSS для нескольких элементов HTML
- Добавить несколько ссылок на классы CSS на один элемент HTML
Как я это себе представляю
- Расширение функций ASP.NET, которые генерируют окончательный HTML
- Захватите весь HTML как строку
- Передайте строку в конструктор для объекта с помощью методов запроса (например, XPATH).
- Просмотрите список глобальных правил, например, для ребенка
ul
из первыхdiv
затемclass = "navigation"
- Просмотрите список правил для конкретной страницы, например, для ребенка
ul
из первыхdiv
затемclass &= " home"
- Получить обработанный HTML из объекта, например, obj.ToString
- ASP.NET для возобновления генерации страницы с использованием обработанного HTML
Итак, что мне нужно знать, это:
- Где / как я могу расширить функции генерации страниц ASP.NET (чтобы получить весь HTML страницы)
- Какие классы имеют методы запроса элементов / узлов и доступ к атрибутам
Заранее благодарны за Вашу помощь.
PS Я занимаюсь разработкой веб-форм ASP.NET с использованием кода VB.net на ISS 7
2 ответа
Проверьте мой проект CsQuery: https://github.com/jamietre/csquery или на nuget как "CsQuery".
Это порт CQ (.NET 4) для jQuery. В базовых тестах производительности (включенных в набор тестов проекта) селекторы примерно в 100 раз быстрее, чем HTML Agility Pack + Fizzler (надстройка селектора CSS для HAP); это достаточно быстро для манипулирования потоком вывода в реальном времени на типичном веб-сайте. Если вы amazon.com или что-то, конечно, YMMV.
Моей первоначальной целью при разработке этого было манипулирование HTML из системы управления контентом. После того, как я его запустил, я обнаружил, что использование CSS-селекторов и jQuery API намного интереснее, чем веб-элементы управления, и начал использовать его в качестве основного инструмента HTML-манипуляции для страниц, отображаемых на сервере, и построил его для почти все CSS, jQuery и браузер DOM. С тех пор я не трогал веб-контроль.
Чтобы перехватить HTML в веб-формах с помощью CsQuery, вы делаете это на странице кода:
using CsQuery;
using CsQuery.Web;
protected override void Render(HtmlTextWriter writer)
{
var csqContext = WebForms.CreateFromRender(Page, base.Render, writer);
// CQ object is like a jQuery object. The "Dom" property of the context
// returned above represents the output of this page.
CQ doc = csqContext.Dom;
doc["li > a"].AddClass("foo");
// write it
csqContext.Render();
}
Чтобы сделать то же самое в ASP.NET MVC, пожалуйста, смотрите это сообщение в блоге, описывающее это.
На GitHub есть базовая документация для CsQuery. Помимо ввода и вывода HTML, он работает почти так же, как jQuery. WebForms
Объект выше, просто чтобы помочь вам справиться с взаимодействием с HtmlTextWriter
объект и Render
метод. Универсальное использование очень просто:
var doc = CQ.Create(htmlString);
// or (useful for scraping and testing)
var doc = CQ.CreateFromUrl(url);
// do stuff with doc, a CQ object that acts like a jQuery object
doc["table tr:first"].Append("<td>A new cell</td>");
Кроме того, почти весь DOM браузера доступен с использованием тех же методов, которые вы используете в браузере. Индексатор [0] возвращает первый элемент в наборе выбора как jquery; Если вы привыкли писать JavaScript для манипулирования HTML, это должно быть очень знакомо.
// "Select" method is the same as the property indexer [] we used above.
// I go back and forth between them to emphasise their interchangeability.
var element = dom.Select("div > input[type=checkbox]:first-child")[0];
a.Checked=true;
Конечно, в C# у вас есть множество других универсальных инструментов, таких как LINQ. В качестве альтернативы:
var element = dom["div > input[type=checkbox]:first-child"].Single();
a.Checked=true;
Когда вы закончите манипулировать документом, вы, вероятно, захотите получить HTML:
string html = doc.Render();
Это все, что нужно сделать. Существует множество методов CQ
объект, охватывающий все методы манипуляции с JQuery DOM. Существуют также служебные методы для обработки JSON, и он имеет обширную поддержку динамических и анонимных типов, чтобы максимально упростить передачу структур данных (например, набор классов CSS) - так же, как jQuery.
Некоторые более продвинутые вещи
Я не рекомендую делать это, если вы не знакомы с работой на низком уровне с http-процессом asp.net. Ничто не может быть отменено, но будет кривая обучения, если вы никогда не слышали о HttpHandler.
Если вы хотите вообще пропустить движок WebForms, вы можете создать IHttpHandler
это автоматически анализирует HTML-файлы. Это определенно будет работать лучше, чем наложение на движок ASPX - кто знает, может быть, даже быстрее, чем выполнять аналогичную обработку на стороне сервера с веб-элементами управления. Затем вы можете зарегистрировать свой обработчик, используя web.config для определенных расширений (например, htm
а также html
).
Еще один способ автоматического перехвата - это маршрутизация. Вы можете без проблем использовать библиотеку маршрутизации MVC в приложении webforms, вот одно описание того, как это сделать. Затем вы можете создать маршрут, который соответствует любому шаблону, который вы хотите (опять же, возможно, *.html
) и передать обработку на заказ IHttpHandler
или класс. В этом случае вы делаете все: вам нужно посмотреть путь, загрузить файл из файловой системы, проанализировать его с помощью CsQuery и направить ответ.
Используя любой из этих механизмов, вам, конечно, понадобится указать вашему проекту, какой код запускать для каждой страницы. То есть, если вы создали изящный HTML-парсер, как вы скажете ему запустить правильный "код позади" для этой страницы?
MVC делает это, просто находя контроллер с именем "PageNameController.cs" и вызывая метод, который соответствует имени параметра. Вы можете делать все, что хотите; Например, вы можете добавить элемент:
<script type="controller" src="MyPageController"></script>
Ваш универсальный код обработчика может искать такой элемент, а затем использовать отражение, чтобы найти правильный именованный класс и метод для вызова. Это довольно сложно, и выходит за рамки этого ответа; но если вы хотите построить совершенно новый фреймворк или что-то в этом роде, вы бы так и поступили.
Перехват содержимого страницы до ее отправки довольно прост. Я сделал это некоторое время назад в проекте, который сжимал контент на лету: http://optimizerprime.codeplex.com/ (Это уродливо, но он сделал свою работу, и вы могли бы спасти часть кода). В любом случае, то, что вы хотите сделать, это следующее:
1) Создайте объект Stream, который сохраняет содержимое страницы до вызова Flush. Например, я использовал это в своем проекте сжатия: http://optimizerprime.codeplex.com/SourceControl/changeset/view/83171 Как я уже говорил ранее, это не красиво. Но я хочу сказать, что вам нужно создать свой собственный класс Stream, который будет делать то, что вы хотите (в этом случае вы получите строковый вывод страницы, проанализируете / измените строку и затем выведете ее для пользователя).
2) Присвойте ему объект фильтра страницы. (Page.Response.Filter) Обратите внимание, что вам нужно сделать это довольно рано, чтобы вы могли поймать весь контент. Я сделал это с модулем HTTP, который выполнялся по событию PreRequestHandlerExecute. Но если вы сделали что-то вроде этого:
protected override void OnPreInit(EventArgs e)
{
this.Response.Filter = new MyStream();
base.OnPreInit(e);
}
Это также, скорее всего, сработает.
3) Вы должны иметь возможность использовать что-то вроде Html Agility Pack для анализа HTML-кода и изменения его оттуда.
Это мне кажется самым простым подходом.