Создание строго типизированных ссылок на контент в ASP .Net MVC с помощью шаблонов T4. Часть 2

В моем предыдущем посте я рассмотрел создание статических ссылок на контент, которые мы используем в ASP .Net с использованием шаблонов T4. Было несколько вопросов, на которые я указал, и некоторые другие, которые мне указали.

<head runat="server">
  <link href="<%= Url.Content(Content.Site) %>" rel="stylesheet" type="text/css" />
</head>

Мой код неверный

Более чем одним способом. Посмотрите на сгенерированный код:

public static class Content
{
    public static class Images
    {
        public const string Add = "~/Content/Content/Images/Add.png";
        public const string Check = "~/Content/Content/Images/Check.png";
        public const string Delete = "~/Content/Content/Images/Delete.png";
        public const string Edit = "~/Content/Content/Images/Edit.png";
        public const string FolderBackground = "~/Content/Content/Images/FolderBackground.gif";
        public const string FolderBottom = "~/Content/Content/Images/FolderBottom.gif";
        public const string FolderTop2 = "~/Content/Content/Images/FolderTop2.gif";
        public const string Guy = "~/Content/Content/Images/Guy.png";
        public const string Mail = "~/Content/Content/Images/Mail.png";
        public const string Papers = "~/Content/Content/Images/Papers.jpg";
    }

    public const string Site = "~/Content/Content/Site.css";
}

Да, я пропустил это — сгенерированные ссылки на самом деле не так. Я очевидно был слишком взволнован, что это действительно работало (после борьбы с монстрами T4 в течение долгого времени). Это легко исправить. Корневой путь должен просто измениться с

void GenerateLinksForFolder(Project mainProject, string folderName)
{
    var projectItem = GetProjectItem(mainProject, folderName);
    RecursivelyIterateThroughFolder(projectItem, string.Format("~/{0}/", folderName));
}

в

void GenerateLinksForFolder(Project mainProject, string folderName)
{
    var projectItem = GetProjectItem(mainProject, folderName);
    RecursivelyIterateThroughFolder(projectItem,"~/");
}

Следующая ошибка, которую я сделал, была связана с отображением тега ссылки для таблицы стилей.

<head runat="server">
  <link href="<%= Url.Content(Content.Site) %>" rel="stylesheet" type="text/css" />
</head>

Предоставленная ссылка выглядит так:

Дэвид Эббо указал на происходящее, а также на очевидный обходной путь.

Когда вы используете выражение с двойными кавычками, анализатор запутывается, потому что они конфликтуют с двойными кавычками для атрибута href. Поэтому он не рассматривает тег ссылки как нечто особенное. Но с улучшенным выражением нет двойных кавычек. Обходной путь? Добавить + »». Я знаю, не красиво, может быть, лучше.

Проблема относится только к разделу head — если я поместил точно такой же код в раздел body, то отрендеренный код будет правильным.

В моем предыдущем посте я также упоминал, что я не заменяю весь вызов Url.Content — я просто пытаюсь удалить зависимость от строк. Однако в этом случае я думаю, что замена всего тега ссылки будет лучшим вариантом.  Я просто добавил 2 метода расширения .

public static class ContentLinkHelpers
{
    public static string Stylesheet(this UrlHelper helper, string content)
    {
        return string.Format("<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />", helper.Content(content));
    }

    public static string Script(this UrlHelper helper, string content)
    {
        return string.Format("<script src=\"{0}\" type=\"text/javascript\"></script>", helper.Content(content));
    }
}

Это позволяет нам отображать таблицу стилей (и сценарии), используя вспомогательные методы.

<head runat="server">
  <%= Url.Stylesheet(Content.Site) %>
  <%= Url.Script(Scripts.Jquery132) %>
</head>

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

Санировать вход

Что-то, что я не упомянул (что на самом деле работает правильно, * вздох *) — это необходимость дезинфицировать входные данные. Например, сценарию с именем Jquery-1.3.2-Vsdoc.js требуется имя переменной, похожее на Jquery132Vsdoc . Я сделал преобразование с помощью регулярного выражения .

return Regex.Replace(name, "[^a-zA-Z0-9_]", string.Empty);

Хотя это будет работать для примера Jquery-1.3.2-Vsdoc.js , нам все равно нужно исключить все ключевые слова C #. Например, изображение с именем « lock » будет генерировать ошибки компиляции, поскольку « lock » является зарезервированным словом.

К сожалению, нет способа получить программный доступ к списку ключевых слов C # — лучшее, что мы можем сделать, — это поддерживать список в коде и проверять этот список. 

foreach(var keyword in keywords)
{
    if (keyword.Equals(sanitized))
    {
        return "@" + sanitized;
    }
}

return sanitized;

Это будет правильно генерировать имена переменных для любого содержимого.

public const string @lock = "~/Content/Images/lock.png";

Использование шаблонов MVC T4

Как я уже упоминал, следующий очевидный шаг — для одного шаблона, который можно включить в любой проект. Благодаря Дэвиду Эббо шаблон MVC T4 (теперь называемый T4MVC) теперь доступен на CodePlex, как одна из загрузок на странице исходного кода ASP.NET MVC v1.0 .

Author: admin

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *