ASP.NET - анализировать / запрашивать HTML перед передачей и вставлять ссылки на классы CSS

Как веб-разработчик, я чувствую, что слишком много времени тратится на CSS. Я пытаюсь найти решение, в котором я могу написать повторно используемые CSS, то есть классы, и ссылаться на эти классы в HTML без дополнительного кода в файлах ASPX или ASCX и т. Д. Или файлов с выделенным кодом. Я хочу посредника, который связывает элементы HTML с классами CSS.

Чего я хочу добиться:

  • Изменить HTML непосредственно перед передачей
  • Выберите элементы в HTML
  • На основе правил, определенных в другом месте (например, в текстовом файле, относящемся к обрабатываемой в данный момент странице):
  • Добавить ссылку на класс CSS для нескольких элементов HTML
  • Добавить несколько ссылок на классы CSS на один элемент HTML

Как я это себе представляю

  1. Расширение функций ASP.NET, которые генерируют окончательный HTML
  2. Захватите весь HTML как строку
  3. Передайте строку в конструктор для объекта с помощью методов запроса (например, XPATH).
  4. Просмотрите список глобальных правил, например, для ребенка ul из первых div затем class = "navigation"
  5. Просмотрите список правил для конкретной страницы, например, для ребенка ul из первых div затем class &= " home"
  6. Получить обработанный HTML из объекта, например, obj.ToString
  7. ASP.NET для возобновления генерации страницы с использованием обработанного HTML

Итак, что мне нужно знать, это:

  1. Где / как я могу расширить функции генерации страниц ASP.NET (чтобы получить весь HTML страницы)
  2. Какие классы имеют методы запроса элементов / узлов и доступ к атрибутам

Заранее благодарны за Вашу помощь.

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-кода и изменения его оттуда.

Это мне кажется самым простым подходом.

Другие вопросы по тегам