Введение

Жидкость — это язык шаблонов с открытым исходным кодом, созданный Shopify и написанный на Ruby. Его можно использовать для добавления динамического содержимого на страницы и для создания широкого спектра пользовательских шаблонов. Пока DotLiquid представляет собой систему шаблонов, перенесенную на платформу .NET из Ruby’s Liquid Markup.

Несмотря на то, что Liquid широко используется, документация для DotLiquid не является исчерпывающей, и поиск руководств для конкретных случаев использования может не принести никаких результатов.

Я сам немного боролся, пытаясь использовать его, особенно со сложными объектами JSON, но в конце концов я добился некоторого успеха.

Мы перейдем непосредственно к тому, как использовать DotLiquid для создания шаблона в Asp.Net Core (.Net 6).


Настраивать

Сначала нам понадобится работающий проект .net. Используя вашу любимую среду IDE, создайте новое веб-приложение Asp.Net Core, используя шаблон MVC:

Меню создания проекта

Если вы предпочитаете использовать тип CLI в этой команде в каталоге, в который вы хотите добавить свой проект:
dotnet new mvc -au None

Затем с помощью диспетчера пакетов Nuget или интерфейса командной строки нам нужно будет добавить DotLiquid упаковка
dotnet add package DotLiquid и
NewtonSoft.Json пакет к проекту
dotnet add package Newtonsoft.Json


Демо

При создании наш проект будет выглядеть так:

Структура проекта

Первый в нашем wwwroot (или webroot) давайте создадим каталог шаблонов и добавим в него файл шаблона, который представляет собой файлы, оканчивающиеся на .liquid расширение и используйте комбинацию объектов, тегов и фильтров, чтобы сделать содержимое динамичным.
короче это нормально HTML синтаксис + некоторый дополнительный синтаксис для логики.

Назовем наш файл example.liquidа пока поставим один div в нем, чтобы проверить, работает ли рендеринг шаблона.

<div>
    <h3>The template content</h3>
</div>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем в HomeController давайте добавим логику для рендеринга шаблона в его Index Метод действия:

 public IActionResult Index()
{
    // we need to read the contents of the template file
    string liquidTemplateContent = System.IO.File.ReadAllText("wwwroot/template/example.liquid");
    // then we parse the contents of the template file into a liquid template
    Template template = Template.Parse(liquidTemplateContent);
    // then we render the template
    string result = template.Render();
    // and then we return the result to the view in a view bag object
    ViewBag.template = result;

    return View();
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем все, что нам нужно сделать, это поместить наш шаблон в наш файл представления, перезаписать содержимое Views/Index.cshtml со следующим:

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    @Html.Raw(ViewBag.template)
</div>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Здесь мы использовали @Html.Raw вспомогательный тег для отображения html внутри шаблона

Наконец, запустите свой проект, чтобы увидеть результат, который должен выглядеть так:
Выполнить Скриншот

Теперь, чтобы использовать динамические данные, давайте начнем с добавления класса с именем Employee в каталог Model, который должен выглядеть следующим образом:

Структура модели сотрудника

Предполагая, что мы хотим отображать данные сотрудников в нашем шаблоне, для обеспечения безопасности DotLiquid не позволяет вам напрямую обращаться к атрибуту Models, как объясняется в их документах:

DotLiquid сосредоточен на том, чтобы сделать ваши шаблоны безопасными. Он делает это, гарантируя, что шаблоны могут получить доступ только к свойствам и методам, которые были специально включены.
Это означает, что вы не можете просто передать экземпляр модели в шаблон и получить прямой доступ к свойствам.

Итак, чтобы включить свойства, нам нужно создать Drop объект, который использует подход opt-in для предоставления данных.
А Drop class — это класс, который наследуется от DotLiquid. Drop class и предоставляет данные, которые мы хотим передать в наш шаблон.

Добавим к нашему Employee учебный класс:

public class EmployeeDrop : Drop
{
    private readonly Employee _employee;

    public EmployeeDrop(Employee employee)
    {
        _employee = employee;
    }

    public string Name => _employee.Name;
    public string Email => _employee.Email;
    public string Phone => _employee.Phone;
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Я не стал добавлять address на данный момент, чтобы показать, что если мы не добавим атрибут к дропу, шаблон не сможет его вывести и вместо этого покажет пустую строку.

Затем в HomeController нам нужно внести следующие изменения в Index метод действия:

 public IActionResult Index()
    {
        // we need to read the contents of the template file
        string liquidTemplateContent = System.IO.File.ReadAllText("wwwroot/template/example.liquid");
        // then we parse the contents of the template file into a liquid template
        Template template = Template.Parse(liquidTemplateContent);
        // then we create a new instance of the model class
        Employee employee = new Employee
        {
            Name = "John Doe",
            Email = "john.doe@example.com",
            Phone = "555-555-5555",
            Address = "123 Main St."
        };

        Hash hash = Hash.FromAnonymousObject(new
        {
            employee = new EmployeeDrop(employee)
        });
        // then we render the template
        string result = template.Render(hash);
        // and then we return the result to the view in a view bag object
        ViewBag.template = result;

        return View();
    }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Не забудем добавить данные в наш example.liquid шаблон:

<div>
    <h3>The template content</h3>
    <p>
        Name: {{ employee.name }}
    </p>
    <p>
        Email: {{ employee.email }}
    </p>
    <p>
        Phone: {{ employee.phone }}
    </p>
    <p>
        Address: {{ employee.address }}
    </p>
</div>
Войти в полноэкранный режим

Выйти из полноэкранного режима

После перезапуска приложения мы получим что-то вроде этого:

Выполнить предварительный просмотр

Обратите внимание, что мы получили пустой адрес, так как мы не указали его в дропе.
Далее сделаем именно так, но вместо обычного string скажем, у нас есть объект JSON, поэтому мы рассмотрим одну из наиболее часто повторяющихся проблем в настоящее время.
в EmployeeDrop давайте добавим Address такой атрибут, мы будем использовать NewtonSoft.Json для десериализации JSON.

public class EmployeeDrop : Drop
{
    // ... old code
    public IDictionary<string, object>? Address =>
        JsonConvert.DeserializeObject<IDictionary<string, object>>(_employee.Address);
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем давайте изменим формат адреса на действительный JSON в Index метод действия:

 public IActionResult Index()
    {
        // ... old code

        var address = @"
        {
            ""Street"" : ""123 Main St"",
            ""City"" : ""Anytown"",
            ""State"" : ""WA"",
            ""Zip"" : ""12345""
        }
        ";
        Employee employee = new Employee
        {
            Name = "John Doe",
            Email = "john.doe@example.com",
            Phone = "555-555-5555",
            Address = address
        };

        // ... old code

        return View();
    }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Последний шаг — использовать новый атрибут внутри нашего шаблона:

<div>
    <h3>The template content</h3>
    <p>
        Name: {{ employee.name }}
    </p>
    <p>
        Email: {{ employee.email }}
    </p>
    <p>
        Phone: {{ employee.phone }}
    </p>
    <p>Address:</p>
    <p>Street: {{ employee.address.Street }}</p>
    <p>City: {{ employee.address.City }}</p>
    <p>State: {{ employee.address.State }}</p>
    <p>Zip: {{ employee.address.Zip }}</p>
</div>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Хотя поля перетаскивания нечувствительны к регистру, знайте, что JSON поля чувствительны к регистру.

А вот и превью:

предварительный просмотр

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

скажем, Employee может иметь несколько адресов, и у нас есть объект JSON, содержащий массив адресов, давайте внесем следующие изменения в Index метод действия:

 public IActionResult Index()
    {
        // old code
        var addresses = @"
        {
            ""Addresses"": [{
                    ""Address"": ""123 Main Street"",
                    ""City"": ""Montreal"",
                    ""State"": ""QC"",
                    ""Zip"": ""H1S1M5"",
                    ""Country"": ""Canada""
                },
                {
                    ""Address"": ""456 Main Street"",
                    ""City"": ""Montreal"",
                    ""State"": ""QC"",
                    ""Zip"": ""H1S1M5"",
                    ""Country"": ""Canada""
                }
            ]
        }";
        Employee employee = new Employee
        {
            Name = "John Doe",
            Email = "john.doe@example.com",
            Phone = "555-555-5555",
            Address = addresses
        };

        // ... old code

        return View();
    }
Войти в полноэкранный режим

Выйти из полноэкранного режима

Чтобы наш шаблон распознавал вложенный JSON, нам нужно использовать собственный конвертер словарей с нашим десериализатором, здесь вы найдете тот, который вы можете использовать, вы можете добавить его как есть в Employee класс, а затем изменить Address атрибут в EmployeeDrop использовать его так:

public class EmployeeDrop : Drop
{
    // ... old code
    public IDictionary<string, object>? Address =>
        JsonConvert.DeserializeObject<IDictionary<string, object>>(_employee.Address, new DictionaryConverter());
}
Войти в полноэкранный режим

Выйти из полноэкранного режима

Последним шагом является изменение шаблона:

<div>
    <h3>The template content</h3>
    <p>
        Name: {{ employee.name }}
    </p>
    <p>
        Email: {{ employee.email }}
    </p>
    <p>
        Phone: {{ employee.phone }}
    </p>
    <p>Addresses:</p>
    <div>
        {% for addr in employee.address.Addresses -%}
            <div>
                <p>Street: {{ addr.Street }}</p>
                <p>City: {{ addr.City }}</p>
                <p>State: {{ addr.State }}</p>
                <p>Zip: {{ addr.Zip }}</p>
                <p>Country: {{ addr.Country }}</p>
            </div>
        {% endfor %}
    </div>
</div>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем после перезапуска вы получите такой предварительный просмотр:

Окончательный предварительный просмотр


Вывод

Надеюсь, в этой статье вы найдете ответы на вопросы о том, как создать шаблон DotLiquid в Asp.Net Core. Я не рассказывал об обычном потоке управления или тегах итераций, поскольку в документации по шаблонам Liquid уже есть все основы, и что хорошо в DotLiquid, так это то, что вы можете использовать практически все из языка шаблонов Liquid как есть, вы можете проверить их документы. здесь.

Вы найдете окончательный код на это Репозиторий на гитхабе.