ASP.NET Core MVC: WebAPI + Entity Framework + Microsoft SQL Server + Angular. Часть 1

Введение

Небольшой курс по созданию простого веб-приложения с помощью технологий ASP.NET Core MVC, фреймворка Entity Framework, СУБД Microsoft SQL Server и фреймворка Angular. Тестировать web API будем через приложение Postman.

Курс состоит из нескольких частей:

  1. Создание web API с помощью ASP.NET Core MVC и Entity Framework Core.
  2. Реализация пользовательского интерфейса на Angular.
  3. Добавление аутентификации в приложение.
  4. Расширение модели приложения и рассмотрение дополнительных возможностей Entity Framework.


Часть 1. Создание web API с помощью ASP.NET Core MVC и Entity Framework Core


В качестве примера будем расматривать уже ставшее классическим — приложение списка дел. Для разработки приложения я буду использовать Visual Studio 2019(в Visual Studio 2017 процесс аналогичен).

Создание проекта

Создадим новый проект ASP.NET Core Web Application в Visual Studio:

Назовем приложение и укажем путь к каталогу с проектом:

И выберем шаблон приложения API:

Модель

Создадим каталог Models и в новый каталог добавим первый класс TodoItem.cs, объекты которого будут описывать некоторые задачи списка дел в приложении:

public class TodoItem {     public int Id { get; set; }     public string TaskDescription { get; set; }     public bool IsComplete { get; set; } } 

В качестве СУБД мы будем использовать Sql Server, а доступ к базе данных будет осуществляться через Entity Framework Core и для начала установим фреймворк через встроенный пакетный менеджер NuGet:

Одним из подходов в работе с Entity Framework является подход «Code-First». Суть подхода заключается в том, что на основе модели приложения(в нашем случае модель представляет единственный класс — TodoItem.cs) формируется струткура базы данных(таблицы, первичные ключи, ссылки), вся эта работа происходит как бы «за кулисами» и напрямую с SQL мы не работаем. Обязательным условием класса модели является наличие поля первичного ключа, по умолчанию Entity Framework ищет целочисленное поле в имени которого присутствует подстрока «id» и формирует на его основе первичный ключ. Переопределить такое поведение можно с помощью специальных атрибутов или используя возможности Fluent API.
Главным компонентом в работе с Entity Framework является класс контекста базы данных, через который собственно и осуществляется доступ к данным в таблицах:

public class EFTodoDBContext : DbContext {     public EFTodoDBContext(DbContextOptions<EFTodoDBContext> options) : base(options)      { }     public DbSet<TodoItem> TodoItems{ get; set; } } 

Базовый класс DbContext создает контекст БД и обеспечивает доступ к функциональности Entity Framework.
Для хранения данных приложения мы будем использовать SQL Server 2017 Express. Строки подключения хранятся в файле JSON под названием appsettings.json:

{   "ConnectionStrings": {     "DefaultConnection": "Server=.\\SQLEXPRESS;Database=Todo;Trusted_Connection=true"   } } 

Далее нужно внести изменения в класс Startup.cs, добавив в метод ConfigureServices() следующий код:

services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"])); 

Метод AddDbContext() настраивает службы, предоставляемые инфраструктурой Entity Framework Core для класса контекста базы EFTodoDBContext. Аргументом метода AddDbContext () является лямбда-выражение, которое получает объект options, конфигурирующий базу данных для класса контекста. В этом случае база данных конфигурируется с помощью метода UseSqlServer() и указания строки подключения.
Определим основные операции для работы с задачами в интерфейсе ITodoRepository:

 public interface ITodoRepository  {     IEnumerable<TodoItem> Get();     TodoItem Get(int id);     void Create(TodoItem item);     void Update(TodoItem item);     TodoItem Delete(int id);  } 

Данный интерфейс позволяет нам не задумываться о конкретной реализации хранилища данных, возможно мы точно не определились с выбором СУБД или ORM фреймворком, сейчас это не важно, класс описывающий доступ к данным будет наследовать от этого интерфейса.
Реализуем репозиторий, который как уже сказано ранее, будет наследовать от ITodoRepository и использовать в качестве источника данных EFTodoDBContext:

public class EFTodoRepository : ITodoRepository {     private EFTodoDBContext Context;     public IEnumerable<TodoItem> Get()     {         return Context.TodoItems;     }     public TodoItem Get(int Id)     {         return Context.TodoItems.Find(Id);     }     public EFTodoRepository(EFTodoDBContext context)     {         Context = context;     }     public void Create(TodoItem item)     {         Context.TodoItems.Add(item);         Context.SaveChanges();     }     public void Update(TodoItem updatedTodoItem)     {         TodoItem currentItem = Get(updatedTodoItem.Id);         currentItem.IsComplete = updatedTodoItem.IsComplete;         currentItem.TaskDescription = updatedTodoItem.TaskDescription;          Context.TodoItems.Update(currentItem);         Context.SaveChanges();         }      public TodoItem Delete(int Id)     {         TodoItem todoItem = Get(Id);          if (todoItem != null)         {             Context.TodoItems.Remove(todoItem);             Context.SaveChanges();         }          return todoItem;     }     } 

Контроллер

Контроллер, реализация которого будет описана ниже, ничего не будет знать о контексте данных EFTodoDBContext, а будет использовать в своей работе только интерфейс ITodoRepository, что позволяет изменить источник данных не меняя при этом контроллера. Такой подход Адам Фримен в своей книге «Entity Framework Core 2 для ASP.NET Core MVC для профессионалов» назвал — паттерн «Хранилище».
Контроллер реализует обработчики стандартных методов HTTP-запросов: GET, POST, PUT, DELETE, которые будут изменять состояние наших задач, описанных в классе TodoItem.cs. Добавим в каталог Controllers класс TodoController.cs со следующим содержимым:

[Route("api/[controller]")] public class TodoController : Controller {     ITodoRepository TodoRepository;      public TodoController(ITodoRepository todoRepository)     {         TodoRepository = todoRepository;     }      [HttpGet(Name = "GetAllItems")]     public IEnumerable<TodoItem> Get()     {         return TodoRepository.Get();     }      [HttpGet("{id}", Name = "GetTodoItem")]     public IActionResult Get(int Id)     {         TodoItem todoItem = TodoRepository.Get(Id);          if (todoItem == null)         {             return NotFound();         }          return new ObjectResult(todoItem);     }      [HttpPost]     public IActionResult Create([FromBody] TodoItem todoItem)      {         if (todoItem == null)         {             return BadRequest();         }         TodoRepository.Create(todoItem);         return CreatedAtRoute("GetTodoItem", new { id = todoItem.Id }, todoItem);     }      [HttpPut("{id}")]     public IActionResult Update(int Id, [FromBody] TodoItem updatedTodoItem)     {         if (updatedTodoItem == null || updatedTodoItem.Id != Id)         {             return BadRequest();         }          var todoItem = TodoRepository.Get(Id);         if (todoItem == null)         {             return NotFound();         }          TodoRepository.Update(updatedTodoItem);         return RedirectToRoute("GetAllItems");     }      [HttpDelete("{id}")]     public IActionResult Delete(int Id)     {         var deletedTodoItem = TodoRepository.Delete(Id);          if (deletedTodoItem == null)         {             return BadRequest();         }          return new ObjectResult(deletedTodoItem);     }  } 

Перед определением класса указан атрибут с описанием шаблона маршрута для доступа к контроллеру: [Route(«api/[controller]»)]. Контроллер TodoController будет доступен по следующему маршруту: https://<ip хоста>:<порт>/api/todo. В [controller] указывается название класса контроллера в нижнем регистре, опуская часть «Controller».
Перед определением каждого метода в контроллере TodoController указан специальный атрибут вида: [<метод HTTP>(«параметр»,Name = «псевдоним метода»)]. Атрибут определяет какой HTTP-запрос будет обработан данным методом, параметр, который передается в URI запроса и псевдоним метода с помощью которого можно переотправлять запрос. Если не указать атрибут, то по умолчанию инфраструктура MVC попытается найти самый подходящий метод в контроллере для обработки запроса исходя из названия метода и указанных параметров в запросе, так, если не указать в контроллере TodoController атрибут для метода Get(), то при HTTP-запросе методом GET: https://<ip хоста>:<порт>/api/todo, инфраструткура определит для обработки запроса метод Get() контроллера.
В своем конструкторе контроллер получает ссылку на объект типа ITodoRepository, но пока что инфраструктура MVC не знает, какой объект подставить при создании контроллера. Нужно создать сервис, который однозначно разрешит эту зависисмость, для этого внесем некотрые изменения в класс Startup.cs, добавив в метод ConfigureServices() следующий код:

services.AddTransient<ITodoRepository, EFTodoRepository>(); 

Метод AddTransient<ITodoRepository, EFTodoRepository>() определяет сервис, который каждый раз, когда требуется экземпляр типа ITodoRepository, например в контроллере, создает новый экземпляр класс EFTodoRepository.
Полный код класса Startup.cs:

public class Startup {     public Startup(IConfiguration configuration)     {         Configuration = configuration;     }      public IConfiguration Configuration { get; }      public void ConfigureServices(IServiceCollection services)     {         services.AddControllers();         services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);         services.AddDbContext<EFTodoDBContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));         services.AddTransient<ITodoRepository, EFTodoRepository>();     }      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)     {         if (env.IsDevelopment())         {             app.UseDeveloperExceptionPage();         }          app.UseHttpsRedirection();         app.UseRouting();         app.UseAuthorization();         app.UseEndpoints(endpoints =>         {             endpoints.MapControllers();         });     }  } 

Миграции

Для того чтобы Entity Framework сгенерировал базу данных и таблицы на основе модели, нужно использовать процесс миграции базы данных. Миграции — это группа команд, которая выполняет подготовку базы данных для работы с Entity Framework. Они используются для создания и синхронизации базы данных. Команды можно выполнять как в консоли диспетчера пакетов (Package Manager Console), так и в Power Shell(Developer Power Shell). Мы будем использовать консоль диспетчера пакетов, для работы с Entity Framework потребуется установить пакет Microsoft.EntityFrameworkCore.Tools:

Запустим консоль диспетчера пакетов и выполним команду Add-Migration Initial:

В проекте появится новый каталог — Migrations, в котором будут хранится классы миграции, на основе которых и будут создаваться объекты в базе данных после выполнения команды Update-Database:

Web API готово, запустив приложение на локальном IIS Express мы можем протестировать работу контроллера.

Тестирование WebAPI

Создадим новую коллекцию запросов в Postman под названием TodoWebAPI:

Так как наша база пуста, протестируем для начала создание новой задачи. В контроллере за создание задач отвечает метод Create(), который будет обрабатывать HTTP запрос отправленный методом POST и будет содержать в теле запроса сериализированный объект TodoItem в JSON формате. Аттрибут [FromBody] перед параметром todoItem в методе Create() подсказывает инфраструктуре MVC, что нужно десериализировать объект TodoItem из тела запроса и передать его в качестве параметра методу. Создадим запрос в Postman, который отправит на webAPI запрос на создание новой задачи:

Метод Create() после успешного создания задачи перенаправляет запрос на метод Get() с псевдонимом «GetTodoItem» и передает в качестве параметра Id только что созданной задачи, в результате чего в ответ на запрос мы получим созданный объект задачи в формате JSON.

Отправив HTTP запрос методом PUT и указав при этом в URI Id(https://localhost:44370/api/todo/1) уже созданного объекта, а в теле запроса передав объект с некоторыми изменениями в формате JSON, мы изменим этот объект в базе:

HTTP запросом с методом GET без указания параметров получим все объекты в базе:

Запрос HTTP с методом DELETE и указанием Id объекта в URI(https://localhost:44370/api/todo/2), удалит объект из базы и вернет JSON с удаленной задачей:

На этом все, в следующей части реализуем пользовательский интерфейс с помощью JavaScript-фреймворка Angular.

ссылка на оригинал статьи https://habr.com/ru/post/513514/

FOSS News №28 – дайджест новостей свободного и открытого ПО за 3–9 августа 2020 года

Всем привет!

Продолжаем дайджесты новостей и других материалов о свободном и открытом ПО и немного о железе. Всё самое главное про пингвинов и не только, в России и мире. Кто пришёл на смену Столлману, экспертный обзор российского GNU/Linux дистрибутива Astra Linux, отчёт SPI о пожертвованиях для Debian и других проектах, создание The Open Source Security Foundation, почему люди отказываются от пиратства и многое другое.

Оглавление

  1. Главные новости
    1. Джеффри Кнаут избран новым президентом Фонда СПО
    2. TAdviser протестировал операционную систему Astra Linux. Экспертный обзор продукта
    3. Отчёт SPI о пожертвованиях Debian, X.Org, systemd, FFmpeg, Arch Linux, OpenWrt и других
    4. Создание The Open Source Security Foundation
    5. Больше никакого йо-хо-хо: почему люди отказываются от пиратства в сети
  2. Короткой строкой
    1. Мероприятия
    2. Новости FOSS организаций
    3. DIY
    4. Юридические вопросы
    5. Ядро и дистрибутивы
    6. Системное
    7. Безопасность
    8. DevOps
    9. Для разработчиков
    10. Пользовательское
    11. Игры
    12. Железо
    13. Разное
  3. Релизы
    1. Ядро и дистрибутивы
    2. Системный софт
    3. Для разработчиков
    4. Специальный софт
    5. Пользовательский софт

Главные новости

Джеффри Кнаут избран новым президентом Фонда СПО

OpenNET пишет: «Фонд Свободного ПО объявил об избрании нового президента, после ухода с данного поста Ричарда Столлмана после обвинений в поведении, недостойном лидера движения СПО, и угроз разрыва отношений с СПО некоторых сообществ и организаций. Новым президентом стал Джеффри Кнаут (Geoffrey Knauth), входивший в совет директоров Фонда СПО с 1998 года и принимающий участие в работе проекта GNU с 1985 года. Джеффри окончил Гарвардский университет со специализацией в области экономики, после чего посвятил свою деятельность компьютерным наукам, которые сейчас преподаёт в колледже Lycoming. Джеффри является сооснователем проекта GNU Objective-C. Кроме английского Джеффри владеет русским и французским языками, а также сносно говорит на немецком и немного на китайском языке. Из интересов также упоминается лингвистика (имеется работа по славянским языкам и литературе) и пилотирование».

Подробности (1, 2 (en))

TAdviser протестировал операционную систему Astra Linux. Экспертный обзор продукта

Аналитический центр TAdviser продолжает серию экспертных обзоров программных продуктов, в этот раз внимание привлекла «российская операционная система» (пожалуй вернее будет «российский дистрибутив GNU/Linux») Astra Linux, а именно её Common Edition. Special Edition собираются разобрать в начале сентября, там должно быть интереснее. Описано присутствие ОС Astra Linux в госструктурах, обозначена методология и сценарии тестирования («Типовой госслужащий» и «Ведомственный ИТ-администратор»), приведены выводы. Кратко – зрелый продукт, годится для импортозамещения.

Подробности

Отчёт SPI о пожертвованиях Debian, X.Org, systemd, FFmpeg, Arch Linux, OpenWrt и других

OpenNET пишет: «Некоммерческая организация SPI (Software in the Public Interest), курирующей приём пожертвований и юридические вопросы (торговые марки, владение активами и т.п.) для таких проектов, как Debian, Arch Linux, LibreOffice … опубликовала отчёт с финансовыми показателями за 2019 год. Общий размер собранных средств составил 920 тысяч долларов (в 2018 году собрали 1.4 млн)». Более всего собрал Debian (343 000 долларов). Для сравнения The Apache Software Foundation собрал $2.2 млн., я ссылался на их отчёт в прошлом выпуске.

Подробности

Создание The Open Source Security Foundation

Становясь всемирным фундаментом разработки программного обеспечения FOSS проекты требуют особого внимания к их безопасности. Это отражает недавнее объединение многих больших компаний в The Open Source Security Foundation для более высокого уровня безопасности FOSS. «В число учредителей OpenSSF вошли такие компании, как GitHub, Google, IBM, JPMorgan Chase, Microsoft, NCC Group, OWASP Foundation и Red Hat. В качестве участников присоединились компании GitLab, HackerOne, Intel, Uber, VMware, ElevenPaths, Okta, Purdue, SAFECode, StackHawk и Trail of Bits. … Работа OpenSSF будет сосредоточена в таких областях, как скоординированное раскрытие информации об уязвимостях и распространение исправлений, разработка инструментов для обеспечении безопасности, публикация лучших практик по безопасной организации разработки, выявление связанных с безопасностью угроз в открытом ПО, проведение работы по аудиту и усилению безопасности критически важных открытых проектов, создание средств для проверки идентичности разработчиков» – сообщает OpenNET.

Подробности (1, 2 (en))

Больше никакого йо-хо-хо: почему люди отказываются от пиратства в сети

На Хабре вышла статья, показывающая примеры отказов от «пиратского использования» как в сфере программных продуктов, так и творческих произведений. Не совсем прямо относится к нашей теме FOSS, но весьма близко, поэтому включено в дайджест. «По уровню распространенности пиратства Россия в настоящее время находится на втором месте в мире. Хотя если брать не общее исследование Muso, а только отчёт о софте, сделанный BSA, то наша страна уже 48-я. … Однако хватает и тех, кто переходит на «светлую сторону силы». Зная, что за каждой цифрой скрываются конкретные люди со своими историями, мы вместе с ALLSOFT без труда нашли их и выяснили, что же побудило каждого отказаться от пиратства, хотя халява, казалось бы, всегда где-то рядом» – пишут авторы. Приведены истории сетевого инженера, iOS-разработчика, совладелицы digital-агентства, управляющего партнёра в веб-студии и метеоролога. Весьма интересны комментарии к статье.

Подробности

Короткой строкой

Мероприятия

  1. GNOME и KDE проведут совместную конференцию Linux App Summit в виртуальном формате [→]

Новости FOSS организаций

  1. Первая встреча после 26 лет совместной разработки FreeDOS [→ (en)]

DIY

  1. Свободная веб-энциклопедия для любых IT-проектов на собственном движке [→]

Юридические вопросы

  1. GPL-код из Telegram взят мессенджером Mail.ru без соблюдения GPL [→]

Ядро и дистрибутивы

  1. Предложение по блокировке драйверов-прослоек, предоставляющих доступ к GPL-вызовам ядра Linux [→ 1, 2]
  2. В Fedora 33 начнёт поставляться официальная редакция для интернета вещей [→]
  3. FreeBSD 13-CURRENT поддерживает не менее 90% популярного оборудования на рынке [→]
  4. Быстрее, выше, сильнее: Clear Linux — самый быстрый дистрибутив для x86-64? [→]

Системное

  1. Дистрибутивы устранили проблемы с обновлением GRUB2 [→]
  2. В OpenBSD-current импортирован LLVM 10 [→]

Безопасность

  1. В Firefox приступили к включению защиты от отслеживания перемещений через редиректы [→]
  2. Уязвимости во FreeBSD [→]

DevOps

  1. Решаем практические задачи в Zabbix с помощью JavaScript [→]
  2. Будущее Prometheus и экосистемы проекта [→]
  3. Современные приложения на OpenShift, часть 2: связанные сборки chained builds [→]
  4. TARS (фреймворк создания микросервисов): внося вклад в Open Source экосистему микросервисов [→ (en)]
  5. Зачем использовать Ingress контроллеры с Kubernetes сервисами [→ (en)]
  6. Cerberus – решение для масштабного непрерывного тестирования [→ (en)]
  7. Используйте свой любимый язык программирования для построения IaC с Pulumi [→ (en)]

Для разработчиков

  1. Началось бета-тестирование PHP 8 [→]
  2. Facebook представил Pysa, статический анализатор для языка Python [→]
  3. Сэмулируй сборку приложения ARM на x86 процессоре на примере Qt [→]
  4. QML Online, проект KDE по запуску QML-кода в браузере, получил возможность простого встраивания в другие сайты [→]
  5. Практикуемся в NLP с Python и NLTK [→ (en)]
  6. Продвинутое руководство по NLP анализу с Python и NLTK [→ (en)]
  7. Создаём и отлаживаем Linux дамп файлы [→ (en)]
  8. Улучшение разработки сетевого функционала с Rust фреймворком Capsule [→ (en)]
  9. 5 советов как сделать документацию приоритетом в Open Source проектах [→ (en)]

Пользовательское

  1. Представлен Firefox Reality PC Preview для устройств виртуальной реальности [→]
  2. Команда fdisk в Linux [→]
  3. Почему Ubuntu не входит в систему [→]
  4. Занимаемся математикой в GNU/Linux консоли вместе с GNU bc [→ (en)]

Игры

  1. Как установить десктоп клиент онлайн-сервиса инди-игр Itch на Ubuntu и другие GNU/Linux дистрибутивы [→]

Железо

  1. Встраиваемый компьютер AntexGate + 3G-модем. Полезные настройки для более стабильного интернет-соединения [→]

Разное

  1. Яндекс предоставил сервер-зеркало для загрузки программ от KDE [→]
  2. NextCloud в качестве сервиса по созданию защищенных ссылок [→]
  3. USB-стек ядра Linux переведён на использование инклюзивных терминов [→]
  4. Чему может научить преподавание программирования на C на YouTube [→ (en)]
  5. Нет необходимости в образовании в области компьютерных наук для того чтобы работать с Open Source программным обеспечением [→ (en)]
  6. 5 причин запустить Kubernetes на своей домашней Raspberry Pi лаборатории [→ (en)]
  7. Как установить Arch Linux на Raspberry Pi 4 [→ (en)]

Релизы

Ядро и дистрибутивы

  1. Релиз Ubuntu 20.04.1 LTS [→ 1, 2 (en)]
  2. Обновление дистрибутива Elementary OS 5.1.7 [→]
  3. Выпуск дистрибутива BSD Router Project 1.97 [→]
  4. ReactOS 0.4.13 CE (Coronavirus Edition) [→]

Системный софт

  1. Выпуск системной библиотеки Glibc 2.32 [→]
  2. Выпуск набора видеодрайверов AMD Radeon 20.30 для Linux [→]
  3. Доступен композитный сервер Wayfire 0.5, использующий Wayland [→]
  4. Релиз http-сервера Apache 2.4.46 с устранением уязвимостей [→]

Для разработчиков

  1. Выпуск компилятора для языка программирования Vala 0.49.1 [→]
  2. Выпуск языка программирования Julia 1.5 [→]

Специальный софт

  1. Выпуск Mastodon 3.2, платформы для создания децентрализованных социальных сетей [→]
  2. Релиз QVGE 0.6.0 (визуальный редактор графов) [→]

Пользовательский софт

  1. Опубликован графический редактор Pinta 1.7, выступающий в роли аналога Paint.NET [→ 1, 2 (en)]
  2. Выпуск свободного офисного пакета LibreOffice 7.0 [→ 1, 2, 3, 4 (en)]
  3. Выпуск браузера Pale Moon 28.12 [→]

На этом всё, до следующего воскресенья!

Высказываю большое спасибо OpenNET, много новостных материалов и сообщений о новых релизах взято с их сайта.

Если кто интересуется составлением обзоров и имеет время и возможность помочь – буду рад, пишите по контактам, указанным в моём профиле, или в личные сообщения.

Подписывайтесь на наш Telegram канал или RSS чтобы не пропустить новые выпуски FOSS News.

Также вам может быть интересен дайджест от opensource.com с новостями последних двух недель, он во многом не пересекается с моим. Кроме того, вышел новый номер близкого нам обзора от единомышленников с сайта «Пингвинус».

← Предыдущий выпуск

ссылка на оригинал статьи https://habr.com/ru/post/514434/

Анатомия backpressure в реактивных потоках

Читая многочисленные статьи по теме реактивных потоков, читатель может прийти к выводу, что:
— backpressure это круто
— backpressure доступно только в библиотеках, реализующих спецификацию reactive streams
— эта спецификация настолько сложна, что не стоит и пытаться ее реализовать самому

В этой статье я попытаюсь показать, что:
— backpressure — это очень просто
— для реализации асинхронного backpressure достаточно сделать асинхронный вариант семафора
— при наличии реализации асинхронного семафора, интерфейс org.reactivestreams.Publisher реализуется в несколько десятков строк кода

Backpressure (обратное давление) — это обратная связь, регулирующая скорость работы производителя данных для согласования со скоростью работы потребителя. В отсутствие такой связи более быстрый производитель может переполнить буфер потребителя либо, если буфер безразмерный, исчерпать всю оперативную память.

В многопоточном программировании эта проблема была решена Дейкстрой, предложившим новый механизм синхронизации — семафор. Семафор можно трактовать как счетчик разрешений. Предполагается, что перед совершением ресурсоемкого действия производитель запрашивает разрешение у семафора. Если семафор пуст, то поток производителя блокируется.

Асинхронные программы не могут блокировать потоки, поэтому не могут обращаться за разрешением к пустому семафору (но все остальные операции с семафором делать могут). Блокировать свое исполнение они должны другим способом. Этот другой способ заключается в том, что они просто покидают рабочий поток, на котором исполнялись, но перед этим организуют свое возвращение к работе, как только семафор наполнится.

Наиболее элегантный способ организовать приостановку и возобновление работы асинхронной программы — это структурировать ее как dataflow актор с портами:
A dataflow model – actors with ports, the directed connections between their ports, and initial tokens. Взято из: A Structured Description Of Dataflow Actors And Its Application

Порты бывают входными и выходными. Во входные порты поступают токены (сообщения и сигналы) от выходных портов других акторов. Если входной порт содержит токены, а выходной имеет место для размещения токенов, то он считается активным. Если все порты актора активны, он отправляется на исполнение. Таким образом, при возобновлении своей работы программа актора может безопасно считывать токены из входных портов и записывать в выходные. В этом нехитром механизме таится вся мудрость асинхронного программирования. Выделение портов как отдельных подобъектов акторв резко упрощает кодирование асинхронных программ и позволяет увеличить их разнообразие комбинированием портов разных типов.

Классический актор Хьюитта содержит 2 порта — один видимый, с буфером для входящих сообщений, другой скрытый бинарный, блокирующийся, когда актор отправляется на исполнение и, таким образом, препятствующий повторному запуску актора до окончания первоначального запуска. Искомый асинхронный семафор — нечто среднее между этими двумя портами. Как и буфер для сообщений, он может хранить много токенов, и как у скрытого порта, эти токены — черные, то есть неразличимые, как в сетях Петри, и для их хранения достаточно счетчика токенов.

На первом уровне иерархии у нас определен класс AbstractActor c тремя вложенными классами — базовый Port и производные AsyncSemaPort и InPort, a также с механизмом запуска актора на исполнение при отсутствии заблокированных портов. Вкратце это выглядит так:

public abstract class AbstractActor {     /** счетчик заблокированных портов */     private int blocked = 0;      protected synchronized void restart() {             controlPort.unBlock();     }      private synchronized void incBlockCount() {         blocked++;     }      private synchronized void decBlockCount() {         blocked--;         if (blocked == 0) {             controlPort.block();             excecutor.execute(this::run);         }     }      protected abstract void turn() throws Throwable;      /** головной метод */     private void run() {         try {             turn();             restart();         } catch (Throwable throwable) {             whenError(throwable);         }     } } 

В него вложен минимальный набор классов-портов:
Port — базовый класс всех портов

    protected  class Port {         private boolean isBlocked = true;          public Port() {             incBlockCount();         }          protected synchronized void block() {             if (isBlocked) {                 return;             }             isBlocked = true;             incBlockCount();         }          protected synchronized void unBlock() {             if (!isBlocked) {                 return;             }             isBlocked = false;             decBlockCount();         }     } 

Асинхронный семафор:

    public class AsyncSemaPort extends Port {         private long permissions = 0;          public synchronized void release(long n) {             permissions += n;             if (permissions > 0) {                 unBlock();             }         }          public synchronized void aquire(long delta) {             permissions -= n;             if (permissions <= 0) {                  // поток исполнения не блокируется                 // но актор не зайдет на следующий раунд исполнения,                 // пока счетчик разрешений не станет опять положительным                 block();             }         }     } 

InPort — минимальный буфер для одного входящего сообщения:

    public class InPort<T> extends Port implements OutMessagePort<T> {         private T item;          @Override         public void onNext(T item) {             this.item = item;             unBlock();         }          public synchronized T poll() {             T res = item;             item = null;             return res;         }     } 

Полную версию класса AbstractActor можно посмотреть здесь.

На следующем уровне иерархии мы имеем три абстрактных актора с определенными портами, но с неопределенной процедурой обработки:

  • класс AbstractProducer — это актор с одним портом типа асинхронный семафор (и внутренним контрольным портом, присутствует у всех акторов по умолчанию).
  • класс AbstractTransformer — обычный актор Хьюита, со ссылкой на входной порт следующего актора в цепочке, куда он отправляет преобразованные токены.
  • класс AbstractConsumer — также обычный актор, но преобразованные токены он никуда не отправляет, при этом он имеет ссылку на семафор производителя, и открывает этот семафор после поглощения входного токена. Таким образом, количество находящихся в обработке токенов поддерживается постоянным, и никакого переполнения буферов не происходит.

На последнем уровне, уже в директории test, определены конкретные акторы, используемые в тестах:

  • класс ProducerActor генерирует конечный поток целых чисел.
  • класс TransformerActor принимает очередное число из потока и отправляет его дальше по цепочке.
  • класс ConsumerActor — принимает и печатает полученные числа

Теперь мы можем построить цепочку асинхронных, параллельно работающих обработчиков следующим образом: производитель — любое количество трансформеров — потребитель

Тем самым мы реализовали backpressure, и даже в более общем виде, чем в спецификации reactive streams — обратная связь может охватывать произвольное число каскадов обработки, а не только соседние, как в спецификации.

Чтобы реализовать спецификацию, надо определить выходной порт, чувствительный к количеству переданных ему с помощью метода request() разрешений — это будет Publisher, и дополнить уже существующий InPort вызовом этого метода — это будет Subscriber. То есть, мы принимаем, что интерфейсы Publisher и Subscriber описывают поведение портов, а не акторов. Но судя по тому, что в списке интерфейсов присутствует также Processor, который никак не может быть интерфейсом порта, авторы спецификации считают свои интерфейсы интерфейсами акторов. Ну что же, мы можем сделать акторы, реализующие все эти интерфейсы, с помощью делегирования исполнения интерфейсных функций соответствующим портам.

Для простоты пусть наш Publisher не имеет собственного буфера и будет писать сразу в буфер Subscriber‘а. Для этого нужно, чтобы какой-либо Subscriber подписался и выполнил request(), то есть, у нас есть 2 условия и, соответственно, нам нужно 2 порта — InPort<Subscriber> и AsyncSemaPort. Ни один из них не подходит в качестве базового для реализации Publisher‘а, так как содержит ненужные методы, поэтому мы сделаем эти порты внутренними переменными:

public class ReactiveOutPort<T> implements Publisher<T>, Subscription, OutMessagePort<T> {     protected AbstractActor.InPort<Subscriber<? super T>> subscriber;     protected AbstractActor.AsyncSemaPort sema;      public ReactiveOutPort(AbstractActor actor) {         subscriber = actor.new InPort<>();         sema = actor.new AsyncSemaPort();     } } 

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

Метод subscribe(Subscriber subscriber) сводится к сохранению подписчика и вызову subscriber.onSubscribe():

    public synchronized void subscribe(Subscriber<? super T> subscriber) {         if (subscriber == null) {             throw new NullPointerException();         }         if (this.subscriber.isFull()) {             subscriber.onError(new IllegalStateException());             return;         }         this.subscriber.onNext(subscriber);         subscriber.onSubscribe(this);     } 

что обычно приводит к вызову Publisher.request(), который сводится к поднятию семафора с помощью вызова AsyncSemaPort.release():

    public synchronized void request(long n) {         if (subscriber.isEmpty()) {             return; // this spec requirement         }         if (n <= 0) {             subscriber.current().onError(new IllegalArgumentException());             return;         }         sema.release(n);     } 

И теперь нам осталось не забыть опускать семафор с помощью вызова AsyncSemaPort.aquire() в момент использования ресурса:

    public synchronized void onNext(T item) {         Subscriber<? super T> subscriber = this.subscriber.current();         if (subscriber == null) {             throw  new IllegalStateException();         }         sema.aquire();         subscriber.onNext(item);     } 

Проект AsyncSemaphore был специально разработан для этой статьи. Он намеренно сделан максимально компактным, чтобы не утомлять читателя. Как результат, он содержит существенные ограничения:

  • Одновременно к Publisher‘у может быть подписано не более одного Subscriber‘а
  • размер входного буфера Subscriber‘а равен 1

Кроме того, AsyncSemaPort не является полным аналогом синхронного семафора — только один клиент может выполнять операцию aquire() у AsyncSemaPort (имеется в виду объемлющий актор). Но это не является недостатком — AsyncSemaPort хорошо выполняет свою роль. В принципе, можно сделать и по другому — взять java.util.concurrent.Semaphore и дополнить его асинхронным интерфейсом подписки (см AsyncSemaphore.java из проекта DF4J). Такой семафор может связывать акторы и потоки исполнения в любом порядке.

Вообще, каждый вид синхронного (блокирующего) взаимодействия имеет свой асинхронный (неблокирующий) аналог. Так, в том же проекте DF4J имеется реализация BlockingQueue, дополненная асинхронным интерфейсом. Это открывает возможность поэтапного преобразования многопоточной программы в асинхронную, по частям заменяя потоки на акторы.

ссылка на оригинал статьи https://habr.com/ru/post/512724/

Laravel-Дайджест (3–9 августа 2020)

Подборка новых статей по фреймворку Laravel. Новая версия с исправлением двух уязвимостей. Книга по оптимизации приложений. Рилтайм чат на сокетах. Соблюдение SRP в Laravel.

Laravel Дайджест

Релизы

Уроки

Видео

Наш Telegram Телеграм-канал — следите за новостями о Laravel.

ссылка на оригинал статьи https://habr.com/ru/post/514394/

Прямой эфир с создателем Doom и Quake Джоном Ромеро: вечер теплых ламповых историй по заявкам

ЗАВТРА, 10 августа в 20:00 пройдет прямой эфир с Джоном Ромеро — создателем игр Doom, Quake и Wolfenstein 3D. Это будет вечер теплых ламповых историй по заявкам: вы задаете вопросы в комментариях, а Джон рассказывает, как все было. Как обычно — смотреть можно на любой удобной площадке.

Ромеро со своим другом Джоном Кармаком поучаствовал в создании самых культовых игр нашего поколения когда ему едва исполнилось 20 лет, их называли Ленноном и Маккартни мира игроиндустрии. Мы уже публиковали интервью с Джоном, которое ntsaplin брал год назад, давайте кратко пробежимся по его истории.

Как родилась звезда геймдева: краткая история Doom

Когда-то маленький Джон (его настоящее имя Альфонсо, но мама звала его именно Джонни) играл в Pacman и понял, какие чудеса может творить гейм-дизайн даже в ограниченных условиях графики и звука.

В 1984 году он создает свою первую игру на бумаге и отправляет в популярный тогда журнал inCider.

Обложка журнала июль, 1984 год

Через три года он попадает в промышленный гейм-дизайн и участвует в портировании игры 2400 A.D. с Apple II на платформу Сommodore64, но вскоре уходит и основывает c друзьями компанию id Software — ту самую, которая выпустит Doom.

Именно тогда сложилось блестящее трио: Том Холл, Джон Ромеро и Джон Кармак

В 1992 году ребята выпускают игру Wolfenstein 3D, которую спонсирует Apogee Software, выписав им аванс в 100 тысяч долларов и пообещав роялти в 50%.

Игра становится культовой, получает признание у критиков и награды от журналов, а объём её продаж оценивается в 200 000 копий к концу 1993 года.

Прямо перед ее выпуском компания решает перейти от «семейного» визуального стиля игр к более взрослому и жёсткому стилю. Ромеро предлагает сделать быстрый экшеновый ремейк игры Castle Wolfenstein, он и геймдизайнер Том Холл разрабатывают максимально быстрый и жестокий шутер, кардинально отличающийся от игр того времени.

Wolfenstein 3D распространялась по условно-бесплатной модели: первый эпизод был бесплатным и подогревал интерес к покупке остальных последующих. Успех был головокружительным, и игра доказывает жизнеспособность условно-бесплатной модели.

Игра создавалась всего 6 месяцев, но положила целый ряд играм будущего, популяризировала жанра шутера от первого лица, стала образцом для быстрых экшен-игр и установила планку технологического исполнения.

А дальше был Doom

Вот что сам Ромеро говорит о создании Doom:

Установка была такая: мы должны сделать величайшую игру на свете. Все самое крутое, что мы только можем представить, мы обязаны добавить в нее. Это был единственный раз, когда мы с таким подходом брались за разработку. И до, и после Doom мы начинали создание проекта, думая, что просто поглядим, что у нас получится, но в тот раз все было иначе. У нас была четкая цель – сделать лучшую игру в нашей жизни

Твердо решив ошарашить мир лучшей игрой тысячелетия и как следует на ней заработать, ребята прекращают сотрудничество с Apogee и переезжают в семиэтажной Town East Tower — здание в форме куба с затемненными окнами.

Town East Tower, где ребята из id Software создавали свой ад

Парни обложились пиццей и начали разрабатывать концепт. Почти сразу же возникли разногласия между ведущим гейм-дизайнером Томом Холлом и Ромеро.

Том Холл, как креативный директор, был решительно настроен создать не очередной бессюжетный шутер от первого лица, а наполненную глубиной, более кинематографичную игру. «Может, нам рассказать историю ученых, находящихся на обратной стороне Луны? — предложил он».

Однако Кармак Тома не поддержал. «Сюжет в игре, — произнес он, — сродни сюжету в порнофильме: конечно, он там предполагается, но не доминирует»

Главных героев планировалось несколько, причем с разными характеристиками: один более живуч и любит дробовики, другой быстро бегает, третий может вспороть брюхо врага штыком. Все это вылилось в написание «Библии Doom» – настоящего дизайн-документа с разжевыванием идей.

С самого начала было ясно, что DOOM будет единственной в своем роде. Самым прорывным и интересным был эффект затемнения, когда виртуальное пространство постепенно погружается в абсолютный мрак. Ромеро моментально разглядел потенциал технологии: когда он увидел эффект затемнения, в его мозгу стали возникать разные образы. «Скажи, а можно ли менять яркость света на лету, — спросил он, — или придется просчитывать все заранее?».

— Ну, — ответил Кармак, — я могу сделать свет динамическим.

— Круто! Тогда пускай у нас будут стробы! Только представь: ты пробегаешь через комнату, и — бз-з-з! бз-з-з! бз-з-з! — свет вырубается!

Члены команды Адриан и Кевин веселились от души, вставляя в игру собственные отсканированные изображения. Поддавшись вдохновению, Адриан отсканировал свои сапоги из змеиной кожи и использовал изображение для получения особой текстуры в одном из уровней игры. Как-то Кевин пришел на работу с разбитой коленкой, и парни отсканировали рану, чтобы впоследствии пустить снимок в дело. В причудливом мире DOOM могло пригодиться все что угодно.

В начале декабря 1993 года работа над DOOM близилась к концу. Парни перестали уходить по вечерам домой и спали прямо на полу, диванах, под рабочими столами, в креслах. Дэйв Тейлор, которого наняли помогать с дополнительным программированием, даже приобрел репутацию человека, который тут же отключался на полу. Чем дольше он играл, тем быстрее проходил все бесконечные коридоры и тем сильнее у него кружилась голова. Через несколько минут столь стремительного бега Дэйв обычно ложился на пол, чтобы немного прийти в себя. И порой засыпал в такие моменты. Но это происходило так часто, что однажды вечером парни взяли скотч и очертили на полу контуры его тела.

В пятницу, 10 декабря, час DOOM наконец пробил. Проведя тридцать часов за тестированием игры на баги, парни были готовы выложить ее в интернет. Радостные, но выжатые как лимон парни попрощались друг с другом и разошлись по домам отдыхать впервые за долгие месяцы. Только Джей остался в офисе — он хотел проследить за тем, как пройдет загрузка. Через полчаса последний бит DOOM отправился в Висконсин. И тут же десять тысяч геймеров накинулись на сайт. Сила их напора была чрезмерной — компьютерная сеть Университета Висконсина упала.

— Боже мой, — сказал Дэвид Джею по телефону. — Я еще никогда в жизни ничего подобного не видел. Игра DOOM взорвала мировое сообщество геймеров.

А теперь снова об эфире: на каком языке пройдет трансляция? Будет ли синхронный перевод?

Джон говорит на английском, но мы помним вашу просьбу найти синхронного переводчика «в теме», поэтому им выступит ​Самат Галимов, автор телеграм-канала и подкаста Запуск завтра, ex-CTO Медузы и большой фанат игры Doom. Он будет все переводить на русский и обратно на сплитскрине.

Так как мы пытаемся отойти от закостеневшего формата интервью и делать нормальный, интересный для коммьюнити контент, мы не заготавливаем вопросы заранее, а спрашиваем вас.

Итак, что бы вы хотели спросить у Ромеро?

Пишите в комментариях — мы будем собирать комментарии до самого начала эфира. 10 самых заплюсованных вопросов Самат задаст Ромеро в прямом эфире. Вопросы можно писать также и в инстаграме.

Еще раз напоминаем, где и когда

На нашем ютубе, по этой ссылке. Не забывайте жать колокольчик.

Начало 10 августа, понедельник, в 20:00. Эфир продлится час.

Ес​ли во время эфира вы будете только с телефоном, то эфир можно посмотреть так же и в нашем инстаграм-аккаунте.

До встречи в эфире!

Приходите тепло зависнуть и поностальгировать​.

ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/514156/