# Урок 1. Форма списка и добавление записей

## Структура web-приложени <a href="#project-structure" id="project-structure"></a>

В папке учебного проекта *\1. Template\Web* лежит проект для создания библиотеки классов Razor, предназначенной для выполнения на серверном приложении Blazor. Проект имеет структуру:

<figure><img src="https://179550091-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeBBbXrZunQbpqGnlXIAy%2Fuploads%2FAhk9cCTDBpYYY5Bx7yED%2Fimage.png?alt=media&#x26;token=a710f246-6a59-4e52-8209-e224d1e8b927" alt=""><figcaption></figcaption></figure>

В папке Pages находятся razor-страницы для создания отрисованного веб-интерфейса на сервере, из которого создаются HTML-код и CSS страницы в ответ на запрос браузера. Страница поступает на клиент уже готовая для просмотра.

Razor-страницы создаются на основе xml-файлов форм, в котрых прописываются все элементы страницы и команды взаимодействия со страницей и данными.

### Стартовая форма <a href="#home_page" id="home_page"></a>

Рассмотрим стартовую форму TemplateStart.xml и ее razor-страницу TemplateStart.razor.

Xml-файл стартовой формы содержит следующий код:

{% code title="TemplateStart.xml" lineNumbers="true" %}

```xml
<?xml version="1.0"?>
<Form Name="home" StartPage="True" FontStyle="TitleFont" ForeColor="Black" ValidationType="Flat">
  <Parameters />  
  <Appearance>...</Appearance>  
  <DataConnections />  
  <Commands />  
  <Conditions />  
  <Executions />
    
  <MyObjects>
    <MyObject Name="Label" Type="Label" Assembly="BaseControls">
      <Top>5</Top>
      <Left>5</Left>
      <Height>50</Height>
      <Width>200</Width>
      <TextAlign>TopLeft</TextAlign>
      <Text>Hello world!</Text>
    </MyObject>
  </MyObjects>
</Form>
```

{% endcode %}

В атрибуте [`Name`](https://wfsys.gitbook.io/workflow-web-forms-syntax#name) тэга `<Form>` указывается системное имя, по которому будет доступна web-страницы в браузере.

В атрибуте [`StartPage`](https://wfsys.gitbook.io/workflow-web-forms-syntax#start_page) тэга `<Form>` указывается признак, что данная страница является стартовой для web-приложения. Web-приложение должно иметь одну и только одну стартовую форму.

{% hint style="warning" %}
Если несколько форм имеют атрибут `StartPage` со значением True, то это приведет к некорректной маршрутизации.

Если ни одна из форм не имеет атрибут `StartPage` со значением True, то попытка обращения к стартовой странице вызовет ошибку 404 (страница не найдена).
{% endhint %}

Содержимое файла TemplateStart.razor соответствующего стартовой странице:

{% code title="TemplateStart.razor" lineNumbers="true" %}

```razor
@page "/"
@page "/home"
@inherits WorkflowForm

<div id="form-content" class="content">
    <PageTitle>@Title</PageTitle>
    <FormLoadingBarControl Form=this></FormLoadingBarControl>
    <FormLockPanel Form=this></FormLockPanel>
    <FormImageViewer Form=this></FormImageViewer>
    <LicenseWarningPanel Form=this></LicenseWarningPanel>
    <HelpDeskPanel Form=this></HelpDeskPanel>
    
    <Label Name="Label" Form=this @ref="label"></Label>

</div>
<style>@this.ContentStyle</style>

@code{
    Label label;

    protected override void AddControlsFromPage()
    {
        controls.Add(label.Name, label.Control);
    }
}
```

{% endcode %}

В начале файла видим две директивы:&#x20;

* `@page "/"` - url-адрес стартовой страницы, соответствует атрибуту `StartPage`;
* `@page "/home"` - url-адрес с именем формы, указанным в атрибуте `Name`.

По этим путям страница будет доступна в браузере.

В xml-файле формы описан один объект Label, и в razor-файле видим его упоминание и добавление в коллекцию controls. Но в razor-файле нет упоминания о тексте, который будет отображаться в этом элементе на web-странице.

### Форма логина <a href="#login_page" id="login_page"></a>

В проекте есть файл TemplateLogin.xml, который подготовлен для создания полноценной web-страницы аутентификации пользователя. На его основе создана razor-страница TemplateLogin.razor, в которой можно видеть только одну директиву `@page "/login"` с именем формы, указанным в атрибуте `Name` тэга `<Form>` xml-файла.  Так как в web-проекте уже есть стартовая страница, то страница логина не может быть стартовой.

Дать имя web-странице для логина можно любое, главное указать это имя в файле конфигурации \Web\appsettings.json в поле [LoginPageUrl](https://wfsys.gitbook.io/wt-knowledge-base/platform-wt/configuration-files/web/appsettings-json#login_page_url):

```json
"LoginPageUrl": "login",
```

Так web-приложение будет знать, на какую web-страницу перенаправлять пользователя, если он еще не прошел аутентификацию, или не проявлял активности в течение определенного времени ([TimeoutInterval](https://wfsys.gitbook.io/wt-knowledge-base/platform-wt/configuration-files/web/appsettings-json#timeout_interval)).

## Обновление web-приложения <a href="#updating-web-app" id="updating-web-app"></a>

При развертывании web-приложения в статье [Добавление web-приложения](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/manual-deployment-project/adding_web-app) razor-страницы уже были сформированы, и нам оставалось только собрать исполняющие файлы кастомной библиотеки и скопировать в серверную папку. Но в ходе практики мы будем редактировать существующие формы и создавать новые, поэтому далее рассмотрим, как обновлять razor-страницы.

При внесении изменений в структуру xml-файла или добавлении новой страницы в web-приложение будем следовать следующему алгоритму:

1. Генерация razor-страниц из xml-файлов;
2. Сборка кастомных бинарников web-приложения;
3. Копирование кастомных бинарников в папку web-приложения серверной части;
4. Запуск web-приложения;
5. Обновление страницы в браузере.

Этот порядок действий будем проделывать если менялась структура элементов формы. Если изменили текст в Label или на Button, то можно только обновить страницу в браузере - такие изменения web-приложение подтянет из xml-файла.

Давайте на стартовую форму добавим новый объект типа TextBox с любым именем и любым текстом. Например:

```xml
<MyObject Name="SomeTextBox" Type="TextBox" Assembly="BaseControls">
  <Top>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="Label">
            <Property Name="Bottom"/>
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Top>
  <Left>
    <Object Name="Label">
      <Property Name="Left"/>
    </Object>
  </Left>
  <Width>200</Width>
  <Text>Some text</Text>
</MyObject>
```

### Генерация razor-страниц <a href="#generation-razor-pages" id="generation-razor-pages"></a>

Генерацию razor-страниц необходимо запускать вручную каждый раз, когда добавляем или удаляем объект в xml-файл или создаем новую форму.

Для генерации razor-страниц используем небольшую утилиту XmlToRazorConverter, которая упрощает процесс генерации.

Скачаем архив ниже и распакуем его в любое удобное место:

{% file src="<https://179550091-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeBBbXrZunQbpqGnlXIAy%2Fuploads%2FpTESbs2hABlTV6an3zw0%2FXmlToRazorConverter.zip?alt=media&token=ab857914-fc1c-40b5-9633-5b118f41cfbb>" %}

В архиве есть файл settings.txt, в котором задается два пути через разделитель "|":

* первый путь - абсолютный путь до папки \1. Template\WebForms с xml-файлами;
* второй путь - абсолютный путь до папки \1. Template\Web\Template\Pages с razor-страницами.

Сейчас пути указаны относительно папки *D:\WT\Projects*, в которую разворачивали учебный проект. Если вы разворачивали проект в другую папку, то скорректируйте пути, чтобы утилита могла корректно работать.

Утилита на основе xml-файлов из первой папки сгенерирует razor-страницы и положит их во вторую папку, при необходимости заменив файлы.

Запустим XmlToRazorConverter.exe:

<figure><img src="https://179550091-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeBBbXrZunQbpqGnlXIAy%2Fuploads%2FnT3yXAB6b1PQjWPl3bA4%2Fimage.png?alt=media&#x26;token=7c26a02b-9c28-4799-9800-b27b46b357a5" alt=""><figcaption></figcaption></figure>

Проверим содержимое файла TemplateStart.razor:

{% code title="TemplateStart.razor" %}

```razor
@page "/"
@page "/home"
@inherits WorkflowForm

<div id="form-content" class="content">
<PageTitle>@Title</PageTitle>
<FormLoadingBarControl Form=this></FormLoadingBarControl>
<FormLockPanel Form=this></FormLockPanel>
<FormImageViewer Form=this></FormImageViewer>
<LicenseWarningPanel Form=this></LicenseWarningPanel>
<HelpDeskPanel Form=this></HelpDeskPanel>

<Label Name="Label" Form=this @ref="label"></Label>

<TextBox Name="SomeTextBox" Form=this @ref="someTextBox"></TextBox>

</div>
<style>@this.ContentStyle</style>

@code{
    Label label;
    TextBox someTextBox;

    protected override void AddControlsFromPage()
    {
        controls.Add(label.Name, label.Control);
        controls.Add(someTextBox.Name, someTextBox.Control);
    }
}
```

{% endcode %}

Видим, что в файле появилось упоминание нового объекта SomeTextBox и добавление его в коллекцию controls.

### Сборка кастомных бинарников <a href="#build_custom_bin" id="build_custom_bin"></a>

Запустим проект \1. Template\Web\Template.sln и пересоберем решение.

Если запущено web-приложение, то его следует остановить - в противном случае операционная система не позволит нам заменить исполняемые файлы.

Скопируем dll-файл из папки *\1. Template\Web\Template\bin\Debug\net6.0* в папку D:\WorkflowEngine\Template\Web, в которую разворачивали web-приложение.

Запустим web-приложение и обновим страницу в браузере.

<figure><img src="https://179550091-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeBBbXrZunQbpqGnlXIAy%2Fuploads%2FTQ1h7u9mDLS0JyqzhqtH%2Fimage.png?alt=media&#x26;token=c18d4f2e-17c9-4419-a3e4-e35d2b1640cf" alt=""><figcaption></figcaption></figure>

Приложение при запуске перенаправило нас на страницу логина, а наши изменения были на стартовой форме. В ближайшее время страница логина нам не понадобиться, поэтому может в файле конфигурации \Web\appsettings.json в поле [LoginPageUrl](https://wfsys.gitbook.io/wt-knowledge-base/platform-wt/configuration-files/web/appsettings-json#login_page_url) указать имя стартовой формы:

```json
"LoginPageUrl": "home",
```

Таким образом web-приложение будет рассматривать стартовую форму как форму логина и перенаправлять на нее.&#x20;

Обновим страницу в браузере

Отлично! Теперь можем приступать к созданию формы списка.

Помните: каждый раз надо будет проходить этот алгоритм, чтобы в браузере увидеть свои изменения!
