Евгений Колесников 3 ヶ月 前
コミット
cbd87e11e5

+ 315 - 0
articles/maui/README.md

@@ -0,0 +1,315 @@
+# Лекция: Разработка приложения "Меню ресторана" на .NET MAUI
+
+## Введение в .NET MAUI
+
+**.NET MAUI** (Multi-platform App UI) - это кроссплатформенный фреймворк для создания нативных мобильных и десктопных приложений. Основные компоненты:
+
+>XAML - язык разметки для создания UI
+>
+>C# - бизнес-логика
+>
+>MVVM (Model-View-ViewModel) - архитектурный паттерн
+>
+>Библиотеки - для работы с сетью, БД и т.д.
+
+**Поддерживаемые платформы**
+
+* Мобильные: iOS, Android
+* Десктоп: Windows (WinUI), macOS (Catalyst)
+* В будущем: Linux (в разработке)
+
+**Ключевые особенности**
+
+* Единая кодовая база на C#
+* Использование XAML для UI
+* Доступ к нативным API платформ
+* Горячая перезагрузка (Hot Reload)
+* Встроенная поддержка MVVM
+
+**.NET MAUI** представляет собой мощную эволюцию кроссплатформенных инструментов Microsoft, сочетающую в себе:
+
+* Многолетний опыт Xamarin
+* Мощь современного .NET
+* Гибкость кроссплатформенной разработки
+* Производительность нативных приложений
+
+Это технология, которая позволяет создавать по-настоящему нативные приложения с экономией времени и ресурсов, что делает ее отличным выбором для современных мобильных и десктопных проектов.
+
+## Оснавная структура страницы
+
+```xml
+<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="SimpleMauiMySQL.MainPage"
+             Title="Меню ресторана">
+
+    <Grid RowDefinitions="*, Auto">
+        <!-- Область меню (верхняя часть) -->
+        <CollectionView Grid.Row="0"
+                       ItemsSource="{Binding MenuProducts}"
+                       SelectionMode="None">
+        </CollectionView>
+
+        <!-- Область корзины (нижняя часть) -->
+        <Frame Grid.Row="1"
+               BackgroundColor="#f0f0f0"
+               Padding="10">
+        </Frame>
+    </Grid>
+</ContentPage>
+```
+
+## Создание модели данных
+
+Создаем класс **Product.cs** для работы с данными из API:
+
+```cs
+public class Product
+{
+    public int id { get; set; }
+    public string title { get; set; }
+    public decimal price { get; set; }
+       
+    
+    public int Quantity { get; set; }
+}
+```
+
+**Объяснение:**
+
+Базовые свойства соответствуют полям из API
+
+>Проверить данные , которые находятся в api можно на сайте https://reqbin.com/
+
+![](./img/1.jpg)
+
+Инициализация в `MainPage`:
+
+```cs
+public partial class MainPage : ContentPage
+{
+    public ObservableCollection<Product> MenuProducts { get; } = new();
+    
+    public MainPage()
+    {
+        InitializeComponent();
+        BindingContext = this;
+    }
+}
+```
+
+## Загрузка и отображение продуктов
+
+Метод загрузки:
+
+```cs
+private async void LoadMenu()
+{
+    try
+    {
+        using var client = new HttpClient();
+        var json = await client.GetStringAsync("https://restaurant.kolei.ru");
+        var products = JsonSerializer.Deserialize<List<Product>>(json);
+        
+        foreach (var p in products)
+        {
+            MenuProducts.Add(p);
+        }
+    }
+    catch (Exception ex)
+    {
+        await DisplayAlert("Ошибка", ex.Message, "OK");
+    }
+}
+```
+
+Вызываем в конструкторе:
+
+```cs
+public MainPage()
+{
+    InitializeComponent();
+    BindingContext = this;
+    LoadMenu(); // Добавляем вызов загрузки
+}
+```
+
+## Добавление кнопок управления количества
+
+```xml
+<CollectionView.ItemTemplate>
+    <DataTemplate>
+        <Frame Margin="10" Padding="10">
+            <Grid ColumnDefinitions="*,Auto,Auto,Auto,Auto">
+                <!-- Название и цена -->
+                <Label Text="{Binding title}" FontSize="16"/>
+                <Label Grid.Column="1" Text="{Binding price, StringFormat='{0:C}'}"/>
+                
+                <!-- Кнопки управления -->
+                <Button Grid.Column="2" Text="-" 
+                        CommandParameter="{Binding .}"
+                        Clicked="DecreaseProduct_Clicked"/>
+                
+                <Label Grid.Column="3" Text="{Binding Quantity}"
+                       VerticalOptions="Center"/>
+                
+                <Button Grid.Column="4" Text="+" 
+                        CommandParameter="{Binding .}"
+                        Clicked="AddToCart_Clicked"/>
+            </Grid>
+        </Frame>
+    </DataTemplate>
+</CollectionView.ItemTemplate>
+```
+
+## Реализуем логику корзины
+
+Добавляем коллекцию корзины:
+
+```cs
+public ObservableCollection<Product> CartItems { get; } = new();
+```
+
+Методы добавления/удаления:
+
+```cs
+private void AddToCart_Clicked(object sender, EventArgs e)
+{
+    if (sender is Button { BindingContext: Product product })
+    {
+        var existing = CartItems.FirstOrDefault(p => p.id == product.id);
+        if (existing != null)
+            existing.Quantity++;
+        else
+        {
+            product.Quantity = 1;
+            CartItems.Add(product);
+        }
+    }
+}
+
+private void DecreaseProduct_Clicked(object sender, EventArgs e)
+{
+    if (sender is Button { BindingContext: Product product })
+    {
+        var item = CartItems.FirstOrDefault(p => p.id == product.id);
+        if (item != null)
+        {
+            if (item.Quantity > 1)
+                item.Quantity--;
+            else
+                CartItems.Remove(item);
+        }
+    }
+}
+```
+
+## Добавляем отображение корзины
+
+Обновляем Frame корзины:
+
+```xml
+<Frame Grid.Row="1" BackgroundColor="#f0f0f0" Padding="10">
+    <StackLayout>
+        <Label Text="Ваша корзина:" FontAttributes="Bold"/>
+        <Label Text="{Binding CartContent}"/>
+        <Label Text="{Binding TotalAmount, StringFormat='Итого: {0:C}'}"
+               FontAttributes="Bold"/>
+        
+        <Button Text="Очистить корзину"
+                Clicked="ClearCart_Clicked"/>
+    </StackLayout>
+</Frame>
+```
+
+## Реализуем логику отображения корзины
+
+Вычисляемые свойства:
+
+```cs
+public string CartContent => 
+    CartItems.Count == 0 ? "Корзина пуста" : 
+    string.Join("\n", CartItems.Select(i => $"{i.title} - {i.Quantity} шт."));
+
+public decimal TotalAmount => 
+    CartItems.Sum(item => item.price * item.Quantity);
+```
+
+Метод очистки:
+
+```cs
+private void ClearCart_Clicked(object sender, EventArgs e)
+{
+    CartItems.Clear();
+}
+```
+
+## Добавляем обновление интерфейса
+
+Метод обновления:
+ 
+```cs
+private void UpdateCart()
+{
+    OnPropertyChanged(nameof(CartContent));
+    OnPropertyChanged(nameof(TotalAmount));
+}
+```
+
+Обновляем методы работы с корзиной:
+
+```cs
+private void AddToCart_Clicked(object sender, EventArgs e)
+{
+    // ... существующая логика ...
+    UpdateCart(); // Добавляем в конце
+}
+
+private void DecreaseProduct_Clicked(object sender, EventArgs e)
+{
+    // ... существующая логика ...
+    UpdateCart(); // Добавляем в конце
+}
+
+private void ClearCart_Clicked(object sender, EventArgs e)
+{
+    CartItems.Clear();
+    UpdateCart(); // Добавляем вызов
+}
+```
+
+При скачивании проекта введите команду `dotnet workload restore` для того чтобы скачать все зависимости и пакеты.
+
+Визуал проекта на Windows:
+
+![](./img/3.png)
+
+Если вы хотите запустить проект на Android, вам понадобится:
+
+Устройство и USB-провод.
+
+Включить режим разработчика на телефоне.
+
+![](./img/7.jpg)
+![](./img/6.jpg)
+
+
+
+Нажмите 11 раз на версию телефона.
+![](./img/5.jpg)
+
+Включите отладку по USB.
+
+Подключите устройство и найдите его в списке, затем запустите проект.
+
+![](./img/8.png)
+
+Также можно запустить проект с помощью эмулятора. Для этого выберите соответствующую опцию:
+
+![](./img/4.png)
+
+После этого начнется скачивание эмулятора и необходимых программ.
+
+Визуал проекта на Android:
+
+![](./img/2.jpg)

BIN
articles/maui/SimpleMaui.zip


BIN
articles/maui/img/1.jpg


BIN
articles/maui/img/2.jpg


BIN
articles/maui/img/3.png


BIN
articles/maui/img/4.png


BIN
articles/maui/img/5.jpg


BIN
articles/maui/img/6.jpg


BIN
articles/maui/img/7.jpg


BIN
articles/maui/img/8.png


+ 347 - 0
articles/web_cs_02.md

@@ -0,0 +1,347 @@
+# MVC. Контроллер: результат действий
+
+## Результаты действий
+
+При обращении к веб-приложению, как правило, пользователь ожидает получить некоторый ответ, например, в виде веб-страницы, которая наполнена данными. На стороне сервера метод контроллера, получая параметры и данные запроса, обрабатывает их и формирует ответ в виде результата действия. Результат действия - это тот объект, который возвращается методом после обработки запроса.
+
+Результатом действия может быть практически что угодно. Например, в прошлых темах использовался объект __string__, например:
+
+```cs
+public string Index()
+{
+    return "Hello METANIT.COM";
+}
+```
+
+Пользователь передает методу некоторые значения и в ответ на запрос видит в своем браузере строку ответа.
+
+Результатом действия может быть какой-нибудь сложный объект:
+
+```cs
+public class HomeController : Controller
+{
+    public Message Index() => new Message("Hello METANIT.COM");
+}
+public record class Message(string Text);
+```
+
+Результатом может быть даже __void__, то есть по сути ничего:
+
+```cs
+public void GetVoid()
+{
+ 
+}
+```
+
+В данном случае метод _GetVoid_ представляет вполне реальное действие контроллера, к которому можно обращаться из адресной строки браузера, передавать параметры, и который может содержать сложную логику обработки запроса. Только после обращения к этому методу пользователь увидит в своем веб-браузере одну пустоту, так как метод ничего не возвращает.
+
+Но в большинстве случаев мы будем иметь дело не с __void__ и даже не с типом __string__, а с объектами типа __IActionResult__, которые непосредственно предназначены для генерации результата действия. Интерфейс __IActionResult__ находится в пространстве имен Microsoft.AspNetCore.Mvc и определяет один метод:
+
+```cs
+public interface IActionResult
+{
+    Task ExecuteResultAsync(ActionContext context);
+}
+```
+
+Метод `ExecuteResultAsync` принимает контекст действия и выполняет генерацию результата.
+
+Этот интерфейс затем реализуется абстрактным базовым классом __ActionResult__:
+
+```cs
+public abstract class ActionResult : IActionResult
+{
+    public virtual Task ExecuteResultAsync(ActionContext context)
+    {
+            ExecuteResult(context);
+            return Task.FromResult(true);
+    }
+ 
+    public virtual void ExecuteResult(ActionContext context)
+    {
+    }
+}
+```
+
+__ActionResult__ добавляет синхронный метод, который выполняется в асинхронном. И если мы вдруг захотим создать свой класс результата действий, то как раз можем либо унаследовать его от ActionResult, либо реализовать интерфейс __IActionResult__.
+
+Итак, создадим свой класс результата действий. Для этого вначале добавим в проект новый класс, который назовем __HtmlResult__
+
+Определим в нем следующий код:
+
+```cs
+public class HtmlResult : IActionResult
+{
+    string htmlCode;
+
+    // конструктор
+    public HtmlResult(string html) => htmlCode = html;
+
+    public async Task ExecuteResultAsync(ActionContext context)
+    {
+        string fullHtmlCode = @$"<!DOCTYPE html>
+        <html>
+            <head>
+                <title>METANIT.COM</title>
+                <meta charset=utf-8 />
+            </head>
+            <body>{htmlCode}</body>
+        </html>";
+        await context.HttpContext.Response.WriteAsync(fullHtmlCode);
+    }
+}
+```
+
+Данный класс будет реализовать интерфейс __IActionResult__. В конструкторе он принимает html-код, который затем будет выводиться на веб-страницу. Для вывода используется асинхронный метод context.HttpContext.Response.WriteAsync()
+
+Теперь используем этот класс в контроллере:
+
+```cs
+public class HomeController : Controller
+{
+    public IActionResult Index()
+    {
+        return new HtmlResult("<h2>Hello METANIT.COM!</h2>");
+    }
+}
+```
+
+Здесь определен метод `Index()`, который возвращает объект __HtmlResult__. При обращении к этому объекту будет срабатывать его метод `ExecuteResultAsync()`, в котором будет происходить генерация html-страницы
+
+Однако в большинстве случаев нам не придется создавать свои классы результатов, потому что фреймворк ASP.NET Core MVC итак предоставляет довольно большую палитру классов результатов для самых различных ситуаций:
+
+- __ContentResult__: отправляет ответ в виде строки
+- __EmptyResult__: отправляет пустой ответ в виде статусного кода 200
+
+    ```cs
+    public IActionResult GetVoid()
+    {
+        return new EmptyResult();
+    }
+    ```
+
+    Аналогичен следующему методу:
+
+    ```cs
+    public void GetVoid()
+    {
+    }
+    ```
+
+- __NoContentResult__: во многом похож на __EmptyResult__, также отправляет пустой ответ, только в виде статусного кода 204
+
+    ```cs
+    public IActionResult GetVoid()
+    {
+        return new NoContentResult();
+    }
+    ```
+
+- __FileResult__: является базовым классом для всех объектов, которые пишут набор байтов в выходной поток. Предназначен для отправки файлов
+- __FileContentResult__: класс, производный от FileResult, пишет в ответ массив байтов
+- __VirtualFileResult__: также производный от FileResult класс, пишет в ответ файл, находящийся по заданному пути
+- __PhysicalFileResult__: также производный от FileResult класс, пишет в ответ файл, находящийся по заданному пути. Только в отличие от предыдущего класса использует физический путь, а не виртуальный.
+- __FileStreamResult__: класс, производный от FileResult, пишет бинарный поток в выходной ответ
+- __ObjectResult__: возвращает произвольный объект, как правило, применяется в качестве базового класса для других классов результатов. Но можно применять и самостоятельно:
+
+    ```cs
+    public class HomeController : Controller
+    {
+        public IActionResult Index()
+        {
+            return new ObjectResult(new Person("Tom", 37));
+        }
+    }
+    record class Person(string Name, int Age);
+    ```
+
+- __StatusCodeResult__: результат действия, который возвращает клиенту определенный статусный код HTTP
+- __UnauthorizedResult__: класс, производный от StatusCodeResult. Возвращает клиенту ответ в виде статусного кода HTTP `401`, указывая, что пользователь не прошел авторизацию и не имеет прав доступа к запрошенному ресурсу.
+- __NotFoundResult__: производный от StatusCodeResult. Возвращает клиенту ответ в виде статусного кода HTTP `404`, указывая, что запрошенный ресурс не найден
+- __NotFoundObjectResult__: производный от ObjectResult. Также возвращает клиенту ответ в виде статусного кода HTTP `404` с дополнительной информацией
+- __BadRequestResult__: производный от StatusCodeResult. Возвращает статусный код `400`, тем самым указывая, что запрос некорректен
+- __BadRequestObjectResult__: производный от ObjectResult. Возвращает статусный код `400` с некоторой дополнительной информацией
+- __OkResult__: производный от StatusCodeResult. Возвращает статусный код `200`, который уведомляет об успешном выполнении запроса
+- __OkObjectResult__: производный от ObjectResult. Возвращает статусный код `200` с некоторой дополнительной информацией
+- __CreatedResult__: возвращает статусный код `201`, который уведомляет о создании нового ресурса. В качестве параметра принимает адрес нового ресурса
+- __ChallengeResult__: используется для проверки аутентификации пользователя
+- __JsonResult__: возвращает в качестве ответа объект или набор объектов в формате JSON
+- __PartialViewResult__: производит рендеринг частичного представления в выходной поток
+- __RedirectResult__: перенаправляет пользователя по другому адресу URL, возвращая статусный код 302 для временной переадресации или код 301 для постоянной переадресации зависимости от того, установлен ли флаг Permanent.
+- __RedirectToRouteResult__: класс работает подобно RedirectResult, но перенаправляет пользователя по определенному адресу URL, указанному через параметры маршрута
+- __RedirectToActionResult__: выполняет переадресацию на определенный метод контроллера
+- __LocalRedirectResult__: перенаправляет пользователя по определенному адресу URL в рамках веб-приложения
+- __ViewComponentResult__: возвращает в ответ сущность ViewComponent
+- __ViewResult__: производит рендеринг представления и отправляет результаты рендеринга в виде html-страницы клиенту
+
+Рассмотрим некоторые из этих классов.
+
+## ContentResult и JsonResult
+
+### ContentResult
+
+ContentResult отправляет клиенту ответ в виде строки. Так, следующий пример:
+
+```cs
+public string Index()
+{
+    return "Hello METANIT.COM";
+}
+```
+
+Можно переписать с использованием ContentResult:
+
+```cs
+public IActionResult Index()
+{
+    return Content("Hello METANIT.COM");
+}
+```
+
+Для отправки ContentResult не надо использовать конструктор, так как в контроллере уже определен специальный метод Content(), который принимает отправляемую строку и создает объект ContentResult.
+
+### JsonResult
+
+Одним из наиболее популярных в наше время форматов хранения и передачи данных является формат JSON (JavaScript Object Notation). JSON не зависит от языка программирования, он более удобен и легче обрабатывается.
+
+В JSON каждый отдельный объект заключается в фигурные скобки и представляет собой набор пар ключ-значение, разделенных запятыми, где ключом является название свойства объекта, а значением соответственно значение этого свойства. Например: {"name":"Tom"}. Здесь "name" является ключом, а "Tom" - значением.
+
+Для отправки объекта в формате json в контроллере имеется метод Json(object obj), который в качестве параметра принимает отправляемый объект. Например:
+
+```cs
+public JsonResult GetName()
+{
+    return Json("Tom");
+}
+```
+
+В данном случае на сторону клиента отправляется строка "Tom".
+
+Допустим, у нас есть следующий класс Person:
+
+```cs
+record class Person(string Name, int Age);
+```
+
+И тогда для отправки клиенту объекта Person мы можем написать следующий метод:
+
+```cs
+public IActionResult Index()
+{
+    Person tom = new Person("Tom", 37);
+    return Json(tom);
+}
+```
+
+При обращении к методу веб-браузер выведет полное описание объекта в формате json
+
+Дополнительная версия метода Json() в качестве второго параметра принимает объект, который задает настройки сериализации в формат json. В качестве такого объекта выступает объект типа JsonSerializerOptions:
+
+```cs
+public class HomeController : Controller
+{
+    public IActionResult Index()
+    {
+        var tom = new Person("Tom", 37);
+        var jsonOptions = new System.Text.Json.JsonSerializerOptions 
+        { 
+            PropertyNameCaseInsensitive = true, // не учитываем регистр
+            WriteIndented = true                // отступы для красоты
+        };
+        return Json(tom, jsonOptions);
+    }
+}
+record class Person(string Name, int Age);
+```
+
+В данном случае объект JsonSerializerOptions задает с помощью свойств параметры сериализации в json. В частности, значение свойства `PropertyNameCaseInsensitive = true` говорит, что регистр названий свойств не учитывается. А свойство `WriteIndented = true` задает установку отступов перед свойствами для более человекопонятного вывода
+
+## Отправка статусных кодов
+
+Нередко возникает необходимость отправить в ответ на запрос какой-либо статусный код. Например, если пользователь пытается получить доступ к ресурсу, который недоступен, или для которого у пользователя нету прав. Либо если просто нужно уведомить браузер пользователя с помощью статусного кода об успешном выполнении операции, как иногда применяется в ajax-запросах. Для этого в ASP.NET Core MVC определена богатая палитра классов, которые можно использовать для отправки статусного кода.
+
+### StatusCodeResult
+
+StatusCodeResult позволяет отправить любой статусный код клиенту:
+
+```cs
+public IActionResult Index()
+{
+    return StatusCode(401);
+}
+```
+
+Для создания этого результата используется метод StatusCode(), в который передается отправляемый код статуса.
+
+Подобным образом мы можем послать браузеру любой другой статусный код. Но для отдельных кодов статуса предназначены свои отдельные классы.
+
+### HttpNotFoundResult и HttpNotFoundObjectResult
+
+NotFoundResult и NotFoundObjectResult посылает код `404`, уведомляя браузер о том, что ресурс не найден. Второй класс в дополнении к статусному коду позволяет отправить доплнительную информацию, которая потом отобразится в браузере.
+
+Объекты обоих классов создаются методом NotFound. Для первого класса - это метод без параметров, для второго класса - метод, который в качестве параметра принимает отправляемую информацию. Например, используем NotFoundObjectResult:
+
+```cs
+public IActionResult Index()
+{
+    return NotFound("Resource not found");
+}
+```
+
+### UnauthorizedResult и UnauthorizedObjectResult
+
+UnauthorizedResult посылает код `401`, уведомляя пользователя, что он не автризован для доступа к ресурсу:
+
+```cs
+public IActionResult Index(int age)
+{
+    if (age < 18) return Unauthorized();
+    return Content("Access is available");
+}
+```
+
+Для создания ответа используется метод Unauthorized().
+
+UnauthorizedObjectResult также посылает код `401`, только позволяет добавить в ответ некоторый объект с информацией об ошибке:
+
+```cs
+public class HomeController : Controller
+{
+    public IActionResult Index(int age)
+    {
+        if (age < 18) return Unauthorized(new Error("Access is denied"));
+        return Content("Access is available");
+    }
+}
+record class Error(string Message);
+```
+
+### BadResult и BadObjectResult
+
+BadResult и BadObjectResult посылают код `400`, что говорит о том, что запрос некорректный. Второй класс в дополнении к статусному коду позволяет отправить доплнительную информацию, которая потом отобразится в браузере.
+
+Эти классы можно применять, например, если в запросе нет каких-то параметров или данные представляют совсем не те типы, которые мы ожидаем получить, и т.д.
+
+Объекты обоих классов создаются методом BadRequest. Для первого класса - это метод без параметров, для второго класса - метод, который в качестве параметра принимает отправляемую информацию:
+
+```cs
+public IActionResult Index(string? name)
+{
+    if (string.IsNullOrEmpty(name)) return BadRequest("Name undefined");
+    return Content($"Name: {name}");
+}
+```
+
+### OkResult и OkObjectResult
+
+OkResult и OkObjectResult посылают код `200`, уведомляя об успешном выполнении запроса. Второй класс в дополнении к статусному коду позволяет отправить дополнительную информацию, которая потом отправляется клиенту в формате json.
+
+Объекты обоих классов создаются методом Ok(). Для первого класса - это метод без параметров, для второго класса - метод, который в качестве параметра принимает отправляемую информацию:
+
+```cs
+public IActionResult Index()
+{
+    return Ok("Don't worry. Be happy");
+}
+```

+ 11 - 88
readme.md

@@ -110,21 +110,14 @@ http://sergeyteplyakov.blogspot.com/2014/01/microsoft-fakes-state-verification.h
 
 * [МДК 05.02. Разработка кода ИС](#мдк-0502-разработка-кода-информационных-систем)
 
-  <!-- - [Основы проектирования информационных систем](#основы-проектирования-информационных-систем) -->
+    - [Проектирование баз данных](#проектирование-баз-данных)
+    - [C# и MySQL](#c-и-mysql)
+    - [Разработка API](#разработка-api)
+    - [Разработка веб приложений (ASP.NET)](#разработка-веб-приложений-aspnet)
+    - [Введение в WEB-разработку](#практика-1-введение-в-web-разработку)
+    - [Разбор заданий прошлых лет](./articles/f6_demo_1.md)
 
-  - [Проектирование баз данных](#проектирование-баз-данных)
-
-  - [C# и MySQL](#c-и-mysql)
-
-  - [Разработка API](#разработка-api)
-
-  - [Введение в WEB-разработку](#практика-1-введение-в-web-разработку)
-
-  <!-- - [Документирование ИС](#документирование-ис) -->
-
-  <!-- - [Практика. Разработка мобильных приложений.](#практика-разработка-мобильных-приложений-android-studio-kotlin) -->
-
-  - [Разбор заданий прошлых лет](./articles/f6_demo_1.md)
+    <!-- - [Документирование ИС](#документирование-ис) -->
 
 * [МДК 05.03. Тестирование информационных систем](#мдк-0503-тестирование-информационных-систем)
 
@@ -134,10 +127,6 @@ http://sergeyteplyakov.blogspot.com/2014/01/microsoft-fakes-state-verification.h
 
 ### Основы проектирования информационных систем
 
-<!-- https://sites.google.com/site/anisimovkhv/learning/pris/lecture -->
-
-<!-- TODO расковырять "практику и методику..." из доки -->
-
 1. [Основные понятия и определения ИС.](./articles/5_1_1_1_intro2.md)
     
 1. [~~Жизненный цикл информационных систем.~~](./articles/5_1_1_2_lifecycle.md)
@@ -228,78 +217,14 @@ https://office-menu.ru/uroki-sql Уроки SQL
 1. ~~Практическая работа «Описание бизнес-процессов заданной предметной области»~~
 -->
 
-<details>
-
-~~<summary><h2>Тема 5.1.2. Система обеспечения качества информационных систем</h2></summary>~~
-
-### ~~Лекции~~
-
-1. [~~Основные понятия качества информационной системы. Национальный стандарт обеспечения качества автоматизированных информационных систем~~](articles/5_1_2_1.md)
-
-1. ~~Международная система стандартизации и сертификации качества продукции. Стандарты группы ISO.~~
-
-1. ~~Методы контроля качества в информационных системах. Особенности контроля в различных видах систем~~
-
-1. ~~Автоматизация систем управления качеством разработки.~~
-
-1. [~~Обеспечение безопасности функционирования информационных систем~~](articles/5_1_2_5.md)
-
-1. ~~Стратегия развития бизнес-процессов. Критерии оценивания предметной области и методы определения стратегии развития бизнес-процессов. Модернизация в информационных системах~~
-
-<!-- [не дописано про госты]: _ -->
-<!-- [https://sites.google.com/site/anisimovkhv/learning/pris/lecture/tema1#p12]: _ -->
-
-### ~~Лабораторные~~
-1. ~~Практическая работа «Построение модели управления качеством процесса изучения модуля «Проектирование и разработка информационных систем»»~~
-2. ~~Практическая работа «Реинжиниринг методом интеграции»~~
-3. ~~Практическая работа «Разработка требований безопасности информационной системы»~~
-4. ~~Практическая работа «Реинжиниринг бизнес-процессов методом горизонтального и/или вертикального сжатия»~~
-
-</details>
-
-<details>
-
-~~<summary><h2>Тема 5.1.3. Разработка документации информационных систем</h2></summary>~~
-
-### ~~Лекции~~
-
-1. ~~Перечень и комплектность документов на информационные системы согласно ЕСПД и ЕСКД. Задачи документирования.~~
-
-1. ~~Предпроектная стадия разработки. Техническое задание на разработку: основные разделы.~~
-
-1. ~~Построение и оптимизация сетевого графика.~~
-
-1. ~~Проектная документация. Техническая документация. Отчетная документация~~
-
-1. [~~Пользовательская документация.~~](./articles/5_1_3_5.md) ~~Маркетинговая документация.~~ 
-
-1. ~~Самодокументирующиеся программы.~~ 
-
-1. ~~Назначение, виды и оформление сертификатов.~~
-
-### ~~Лабораторные~~
-1. ~~Практическая работа «Проектирование спецификации информационной системы индивидуальному заданию»~~
-1. ~~Практическая работа «Разработка общего функционального описания программного средства по индивидуальному заданию»~~
-1. ~~Практическая работа «Разработка руководства по инсталляции программного средства по индивидуальному заданию»~~
-1. ~~Практическая работа «Разработка руководства пользователя программного средства по индивидуальному заданию»~~
-1. ~~Лабораторная работа «Изучение средств автоматизированного документирования»~~
-
-</details>
-
 ### C# и MySQL.
 
 1. [Создание подключения к БД MySQL. Получение данных с сервера. Вывод данных согласно макету (ListBox, Image). Вывод данных плиткой.](./articles/cs_mysql_connection3.md)
-
 1. [Пагинация, сортировка, фильтрация, поиск](./articles/cs_pagination2.md)<!-- datepicker -->
-
 1. [Подсветка элементов по условию. Массовая смена цены продукции.](./articles/cs_coloring2.md)
-
 1. [Создание, изменение, удаление продукции](./articles/cs_edit_product2.md)
-
 1. [Вывод списка материалов продукта. CRUD материалов продукта](./articles/cs_product_material.md)
-
 1. [Разное](./articles/cs_misc.md)
-
 1. [Avalonia](./articles/avalonia.md)
 
 ---
@@ -312,23 +237,21 @@ https://office-menu.ru/uroki-sql Уроки SQL
 ### Разработка API.
 
 1. [API. REST API. Создание сервера ASP.NET Core. Swagger.](./articles/api_asp_net_core.md)
-
 1. [Авторизация и аутентификация. Методы авторизации. Basic-авторизация.](./articles/api_auth.md)
-
 1. [Системы миграции данных.](./articles/migrations.md)
-
 1. [HTTP запросы в C#.](./articles/cs_http.md)
 
 ### Разработка веб приложений (ASP.NET)
 
 1. [Введение в веб-разработку](./articles/web_intro.md)
 1. [Введение в ASP.NET Core MVC. Создание веб-приложения, структура проекта, контроллеры](./articles/web_cs_01.md)
-
-<!-- https://metanit.com/sharp/aspnetmvc/1.1.php -->
+1. [MVC. Контроллер: результат действий](./articles/web_cs_02.md)
 
 ### Разработка мобильных приложений (MAUI)
 
-1. [Что такое MAUI, создание мобильного приложения для Android используя VSC](./articles/cs_maui.md)
+1. [Что такое MAUI, создание мобильного приложения для Android](./articles/maui/README.md)
+
+<!-- (./articles/cs_maui.md) -->
 
 
 <!-- **Лабораторные работы** -->