Posted on 6. June 2024

Рефакторинг коду з використанням псевдонімів будь-якого типу

Рефакторинг коду з використанням псевдонімів будь-якого типу

Ця стаття є третьою в серії з чотирьох частин, в яких ми розглянемо різні можливості C# 12. У цій частині ми зануримося у функцію «псевдонім будь-якого типу», яка дозволяє створювати псевдонім для будь-якого типу за допомогою директиви using. Ця серія статей дійсно починає набувати гарних рис:


  1. Рефакторинг вашого C# коду за допомогою первинних конструкторів

  2. Рефакторинг вашого C# коду за допомогою виразів колекцій

  3. Рефакторинг C# коду за допомогою псевдонімів для будь-яких типів (ця стаття)

  4. Рефакторинг вашого C# коду для використання лямбда-параметрів за замовчуванням

 

Всі ці можливості продовжують наш шлях до того, щоб зробити наш код більш читабельним і зручним для супроводу, і вважаються «повсякденними можливостями C#», які повинні знати розробники. Давайте зануримося!

Псевдонім будь-якого типу *️⃣

У C# 12 з'явилася можливість псевдонімізувати будь-який тип за допомогою директиви using. Ця функція дозволяє вказувати псевдоніми, які відображаються на інші типи. Це стосується типів кортежів, вказівників, масивів і навіть не відкритих узагальнених типів, і всі вони будуть доступні у вашому коді. Ця можливість є особливо корисною:


  • При роботі з довгими або складними іменами типів.

  • Коли вам потрібно розмежувати типи і вирішити потенційні конфлікти імен.

  • При визначенні типів кортежів значень, які ви маєте намір спільно використовувати у збірці.

  • Коли ви хочете додати ясності до вашого коду, використовуючи більш описові імена.

Офіційна документація C# містить багато прикладів використання цієї можливості, але замість того, щоб повторювати ці приклади тут, я вирішив написати демонстраційну програму, яка ілюструє різні аспекти цієї можливості.

Типи посилань з нульовим значенням

_________________________________________________________________________

 

Ця функція підтримує більшість типів, за єдиним винятком типів посилань, які можна обнулити. Тобто, ви не можете створити псевдонім для nullable reference type, і компілятор C# повідомить про помилку CS9132: Using alias cannot be a nullable reference type. Наступні біти були вилучені зі специфікації функції, щоб допомогти прояснити цей момент:

Зразок додатку: Спостереження НЛО 🛸 

Демонстраційний додаток доступний на GitHub за адресою IEvangelist/alias-any-type. Це простий консольний додаток, який імітує спостереження за непізнаними літаючими об'єктами (НЛО). Якщо ви хочете приєднатися до нього локально, ви можете зробити це будь-яким з наведених нижче способів у робочій директорії на ваш вибір:

За допомогою Git CLI:

git clone https://github.com/IEvangelist/alias-any-type.git


За допомогою GitHub CLI:

gh repo clone IEvangelist/alias-any-type

Завантажте zip-файл:


Якщо ви бажаєте завантажити вихідний код, zip-файл доступний за наступною URL-адресою:

Щоб запустити програму, з кореневого каталогу виконайте наступну команду .NET CLI:

dotnet run --project ./src/Alias.AnyType.csproj


Коли програма запускається, вона друкує вступ до консолі і чекає на введення даних користувачем, перш ніж продовжити роботу.


Після натискання будь-якої клавіші, наприклад, клавіші Enter, програма випадковим чином генерує дійсні координати (широту і довготу), а потім, використовуючи ці координати, отримує метадані геокоду, пов'язані з координатами. Координати представлені у форматі градусів-хвилин-секунд (включаючи кардинальність). Під час роботи програми обчислюються відстані між згенерованими координатами, які подаються як спостереження НЛО.



Щоб зупинити програму, натисніть клавіші Ctrl + C.


Хоча цей додаток простий, він включає в себе інші частини C#, які не обов'язково мають відношення до нашої теми в цій статті. Я намагатимусь не зачіпати периферійні теми, але торкатимусь їх, коли вважатиму їх важливими.

Покрокове ознайомлення з кодом 👀

 

Ми використаємо цей розділ, щоб разом пройтися по коду. Є кілька цікавих аспектів коду, які я хотів би висвітлити, включаючи файл проекту, GlobalUsings.cs, деякі розширення та файл Program.cs. З наявного коду є кілька речей, які ми не будемо розглядати, наприклад, моделі реагування та деякі утилітарні методи.


Почнемо з розгляду файлу проекту:
Перше, на що слід звернути увагу, це те, що властивість ImplicitUsings має значення enable. Ця властивість з'явилася у C# 10 і дозволяє цільовому SDK (у цьому випадку Microsoft.NET.Sdk) неявно включати набір просторів імен за замовчуванням. Різні SDK включають різні простори імен за замовчуванням, для отримання додаткової інформації див. документацію про неявне використання директив.

Директиви неявного використання 📜


Елемент ImplicitUsing є особливістю MS Build, тоді як ключове слово global є особливістю мови C#. Оскільки ми обрали глобальне використання, ми також можемо скористатися цією можливістю, додавши наші власні директиви. Одним із способів додавання цих директив є додавання елементів Using у групу ItemGroup. Деякі директиви використання додаються з атрибутом Static, встановленим у true, що означає, що всі їхні static члени доступні без обмежень - докладніше про це пізніше. Атрибут Alias використовується для створення псевдоніма для типу, у цьому прикладі ми вказали псевдонім AsyncCancelable для типу System.Runtime.CompilerServices.EnumeratorCancellationAttribute. У нашому коді тепер ми можемо використовувати AsyncCancelable як псевдонім типу для атрибуту EnumeratorCancellation. Інші елементи Using створюють нестатичні та неалієсовані директиви global using для відповідних просторів імен.

 

Закономірність, що з'являється 🧩 

 

Ми починаємо спостерігати, як у сучасних кодових базах .NET з'являється загальний шаблон, коли розробники визначають файл GlobalUsings.cs для інкапсуляції всіх (або більшості) директив використання в одному файлі. Ця демонстраційна програма слідує цьому шаблону, давайте подивимось на файл далі:


Все у цьому файлі є директивою global using, що робить типи псевдонімів, статичні члени або простори імен доступними у всьому проекті. Перші три директиви призначені для загальних просторів імен, які використовуються у багатьох місцях програми. Наступна директива - це директива global using static для простору імен System.Math, яка робить всі статичні члени Math доступними без обмежень. Решта директив - це директиви global using, які створюють псевдоніми для різних типів, включаючи кілька кортежів, потік координат і CancellationTokenSource, на яке тепер можна просто посилатися через Signal.


Варто врахувати, що коли ви визначаєте тип псевдоніма кортежу, ви можете легко перейти до типу record, якщо вам потрібно додати поведінку або додаткові властивості. Наприклад, пізніше ви можете вирішити, що дійсно хочете додати деяку функціональність до типу Coordinates, ви можете легко змінити його на тип record:


 

Коли ви визначаєте псевдонім, ви фактично створюєте не тип, а ім'я, яке посилається на існуючий тип. У випадку визначення кортежів, ви визначаєте форму кортежу значень. Коли ви називаєте тип масиву псевдонімом, ви не створюєте новий тип масиву, а скоріше називаєте його псевдонімом, можливо, з більш описовою назвою. Наприклад, коли я визначаю API, який повертає IAsyncEnumerable<CoordinateGeoCodePair>, це дуже багато для написання. Натомість тепер я можу посилатися на тип, що повертається, як CoordinateStream у своїй кодовій базі.

Посилання на псевдоніми 📚

 

Було визначено декілька псевдонімів, деякі у файлі проекту, а інші у файлі GlobalUsings.cs. Давайте подивимося, як ці псевдоніми використовуються у коді. Почнемо з розгляду файлу верхнього рівня Program.cs:

 

У попередньому фрагменті коду показано, як псевдонім Signal використовується для створення екземпляру CancellationTokenSource. Як ви знаєте, клас CancellationTokenSource є реалізацією IDisposable, тому ми можемо використовувати інструкцію using, щоб гарантувати, що екземпляр Signal буде належним чином утилізовано, коли він вийде за межі області видимості. Ваша IDE розуміє ці псевдоніми, і коли ви наведете на них курсор, ви побачите фактичний тип, який вони представляють. Погляньте на наступний знімок екрана:


Вступ записується на консоль з виклику WriteIntroduction, безпосередньо перед входом в try / catch. Блок try містить цикл await foreach, який перебирає IAsyncEnumerable<CoordinateGeoCodePair>. Метод GetCoordinateStreamAsync визначено в окремому файлі. Я частіше використовую функціональність partial class, коли пишу програми верхнього рівня, оскільки це допомагає ізолювати проблеми. Уся функціональність, що базується на HTTP, визначена у файлі Program.Http.cs, давайте зосередимося на методі GetCoordinateStreamAsync:


 

Ви помітите, що він повертає псевдонім CoordinateStream, який є IAsyncEnumerable<CoordinateGeoCodePair>. Він приймає атрибут AsyncCancelable, який є псевдонімом для типу EnumeratorCancellationAttribute. Цей атрибут використовується для оформлення маркера скасування таким чином, щоб він використовувався разом з IAsyncEnumerable для підтримки скасування. Поки скасування не запитується, метод генерує випадкові координати, отримує метадані геокоду і повертає новий екземпляр CoordinateGeoCodePair. Метод GetGeocodeAsync запитує метадані геокоду для заданих координат, і у разі успіху повертає модель відповіді GeoCode. Наприклад, Microsoft Campus має такі координати:

Щоб переглянути JSON, відкрийте це посилання у вашому браузері. Тип CoordinateGeoCodePair не є псевдонімом, але це readonly record struct, яка містить Coordinates та GeoCode:

Повертаючись до класу Program, коли ми повторюємо кожну пару координати-геокод, ми деконструюємо кортеж на екземпляри типу Coordinates і GeoCode. Тип Coordinates є псевдонімом для кортежу з двох double значень, що представляють широту і довготу. Знову ж таки, наведіть курсор на цей тип у вашому IDE, щоб швидко побачити тип, подивіться на наступний знімок екрана:


Тип GeoCode  - це модель відповіді, яка містить інформацію про метадані геокоду. Потім ми використовуємо метод розширення, щоб перетворити Coordinates в кардиналізований рядок, який є рядковим представленням координат у форматі градусів-хвилин-секунд. Особисто мені подобається, як легко використовувати псевдоніми у вашій кодовій базі. Давайте розглянемо деякі методи розширення, які розширюють або повертають псевдонімні типи:

 

 

Цей метод розширення розширює тип псевдоніма Coordinates і повертає рядкове представлення координат. Він використовує метод розширення ToDMS для перетворення широти і довготи у формат градусів-хвилин-секунд. Метод розширення ToDMS визначається наступним чином:

Якщо ви пам'ятаєте, псевдонім DMS - це кортеж з трьох значень, що представляють градуси, хвилини та секунди. Метод розширення ToDMS приймає значення double і повертає кортеж DMS. Метод розширення ToCardinal використовується для визначення кардинального напрямку координат і повертає значення N, S, E або W. Методи Abs, Sign і Floor є статичними членами простору імен System.Math, псевдонім якого міститься у файлі GlobalUsings.cs.


Крім того, програма відображає деталі спостереження НЛО на консолі, включаючи координати, метадані геокоду та відстань, пройдену між спостереженнями. Це відбувається постійно, доки користувач не зупинить програму комбінацією клавіш Ctrl + C.

Наступні кроки 🚀

Не забудьте спробувати це у своєму власному коді! Поверніться до останньої частини цієї серії статей, де ми розглянемо параметри лямбда за замовчуванням. Щоб продовжити дізнаватися більше про цю функцію, відвідайте наступні ресурси:

 




Posted on 4. April 2024

Announcing .NET MAUI in .NET 8 Preview 6: Hello VS Code & VS for Mac

Анонс .NET MAUI у .NET 8 Preview 6: Hello VS Code & VS для Mac

.NET MAUI тепер доступний у .NET 8 Preview 6, в якому вирішено 23 важливих проблеми та впроваджено Native AOT для iOS. Крім того, сьогодні ви можете насолоджуватися .NET MAUI в .NET 8, використовуючи нове розширення .NET MAUI для коду Visual Studio, а також з випуском 17.6.1 Visual Studio для Mac.

Також доступний новий сервісний випуск .NET 7. Докладнішу інформацію можна знайти у примітках до випуску. Наразі команда зосереджена на якості .NET 8, а це означає, що для .NET 7 будуть випущені лише найважливіші виправлення. 

Виправлення та покращення в .NET MAUI

Вирішено декілька важливих проблем, пов'язаних зі шрифтами (#9104, #13239), навігацією (#7698, #15488, #9938), вкладками (#12386, #13239, #6929) та файловим провідником (#11088). Команда також продовжує роботу над покращенням керування пам'яттю та усуненням витоку адрес (#15062, #15303, #15831).

.NET 8 preview 6 представляє Native AOT (попередня компіляція) для iOS. Використовуючи цю функцію попереднього перегляду, ми спостерігаємо зменшення розміру додатків на 30-40% порівняно з Mono. Якщо вас зацікавила можливість досягти кращої продуктивності та зменшення розміру додатків для iOS, ознайомтеся з подробицями у статті про .NET 8 preview 6 у блозі.

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

Представляємо VS Code (Preview)

На сьогодні вже випущено розширення .NET MAUI для Visual Studio Code, що забезпечує однаковий досвід розробки для Windows, macOS та Linux. Щоб дізнатися більше про розширення, прочитайте статтю Медді Монтакіли в блозі, де вона розповідає про нього.

screenshot of Visual Studio Code debugging a .NET MAUI app in an Android emulator

Як оновити

Visual Studio 2022 для Windows тепер містить попередні версії .NET 8 та робоче навантаження .NET MAUI. Завантажте останню попередню версію (17.7 Preview 3), виберіть робоче навантаження .NET Multi-platform App UI, а потім позначте додатковий компонент ".NET MAUI (.NET 8 Preview)".

Visual Studio installer checkbox for .NET MAUI and .NET 8 previews

Якщо ви використовуєте macOS, то тепер можете програмувати за допомогою Visual Studio для Mac, увімкнувши функцію попереднього перегляду для .NET 8 у Параметрах і встановивши .NET 8 preview 6 з інсталятора.

Enable .NET 8 in Visual Studio 2022 for Mac

Завантажте інсталятор .NET 8 preview 6, а потім встановіть .NET MAUI з командного рядка:

dotnet workload install maui


Поділіться своїми відгуками!

Ваші відгуки та внески в .NET MAUI дуже цінні. Ви можете повідомляти про проблеми, пропонувати функції або надсилати запити у репозиторії GitHub. Також ви можете приєднатися до сервера Discord або слідкувати за командою у Twitter, щоб бути в курсі останніх новин та оновлень.

 

Дякуємо за вашу підтримку і щасливого кодування!

Source



Posted on 10. December 2023

.NET 8 Networking Improvements

Покращення роботи з мережею в .NET 8

Вже стало традицією публікувати в блозі повідомлення про нові цікаві зміни в мережевому просторі з новим випуском .NET . Цього року ми хотіли б запровадити зміни в просторі HTTP , нові додані метрики, нові API HttpClientFactory, тощо.


HTTP

Метрики

.NET 8 додає вбудовані HTTP-метрики як до ASP.NET Core, так і до HttpClient, за допомогою System.Diagnostics.Metrics API, який був представлений у .NET 6. І API-інтерфейси Metrics, і семантика нових вбудованих показників були розроблені у тісній співпраці з OpenTelemetry, переконуючись, що нові показники відповідають стандарту та добре працюють із такими популярними інструментами, як Prometheus і Grafana. .

API System.Diagnostics.Metrics представляє багато нових функцій, яких не було в EventCounters. Ці функції широко використовуються новими вбудованими метриками, що призводить до ширшої функціональності, досягнутої простішим і елегантнішим набором інструментів. Наведу кілька прикладів:

Гістограми дозволяють нам повідомляти про тривалості, напр. тривалість запиту ( http.client.request.duration) або тривалість з’єднання (http.client.connection.duration). Це нові показники без відповідників EventCounter.

Багатовимірність дозволяє нам додавати теги (атрибути або мітки) до вимірювань, що означає, що ми можемо повідомляти таку інформацію, як server.address (ідентифікує джерело URI) або error.type (описує причину помилки, якщо запит не вдається) разом із вимірюваннями. Багатовимірність також забезпечує спрощення: для звітування про кількість відкритих HTTP-з’єднань SocketsHttpHandler використовує 3 EventCounters: http11-connections-current-total, http20-connections-current-totalіhttp30-connections-current-total , тоді як еквівалент цих лічильників Metrics є одним інструментом, http.client.open_connections, де версія HTTP повідомляється за допомогою тегу network.protocol.version.

Щоб допомогти використати випадки, коли вбудованих тегів недостатньо для класифікації вихідних HTTP-запитів, метрика http.client.request.duration підтримує впровадження тегів, визначених користувачем. Це називається збагаченням.

Інтеграція IMeterFactory дозволяє ізолювати екземпляри Meter, які використовуються для випромінювання метрик HTTP, що полегшує написання тестів, які перевіряють вбудовані вимірювання, і дозволяє паралельне виконання таких тестів.

– Хоча це не стосується вбудованих мережевих метрик, варто зазначити, що API колекції System.Diagnostics.Metrics також є більш досконалими: вони суворо типізовані та більш продуктивні та відкривають кільком слухачам одночасно доступ до неагрегованих вимірювань.

Ці переваги разом призводять до кращих, багатших показників, які можна ефективніше збирати сторонніми інструментами, такими як Prometheus. Завдяки гнучкості PromQL (Prometheus Query Language) , яка дозволяє створювати складні запити на основі багатовимірних показників, зібраних із мережевого стеку .NET, користувачі тепер можуть отримувати статистичні дані про стан і працездатність екземплярів HttpClient та SocketsHttpHandler на рівні, який не був раніше можливим.

З іншого боку, слід зазначити, що лише компоненти System.Net.Http та System.Net.NameResolution інструментуються за допомогою System.Diagnostics.Metrics у .NET 8, а це означає, що вам все одно потрібно використовувати EventCounters для отримання лічильників із нижчих рівнів стеку, таких як System.Net.Sockets. Хоча всі вбудовані лічильники подій, які існували в попередніх версіях, все ще підтримуються, команда .NET не очікує значних нових інвестицій у лічильники подій, і нові вбудовані інструменти будуть додані, використовуючи System.Diagnostics.Metrics, в майбутніх версіях.

Щоб отримати додаткові відомості про використання вбудованих метрик HTTP, прочитайте наш підручник щодо мережевих метрик у .NET . Він містить приклади збирання та звітування за допомогою Prometheus і Grafana, а також демонструє, як збагачувати та тестувати вбудовані HTTP-метрики. Щоб отримати вичерпний список вбудованих інструментів, перегляньте документацію для метрик System.Net . Якщо вас більше цікавить серверна сторона, будь ласка, прочитайте документацію про показники ASP.NET Core.

Розширена телеметрія

Окрім нових показників, наявні телеметричні події EventSource, представлені в .NET 5, були доповнені додатковою інформацією про HTTP-з’єднання ( dotnet/runtime#88853 ):

Тепер, коли встановлюється нове з’єднання, подія логує connectionId разом із схемою, портом та IP-адресою однорангового пристрою. Це дає змогу співвідносити запити та відповіді зі з’єднаннями через подію RequestHeadersStart, яка виникає, коли запит пов’язується з об’єднаним з’єднанням і починає оброблятися, яка також реєструє пов’язані connectionId. Це особливо цінно в діагностичних сценаріях, коли користувачі хочуть бачити IP-адреси серверів, які обслуговують їхні HTTP-запити, що було основною мотивацією додавання ( dotnet/runtime#63159 ).

 

Події можна використовувати багатьма способами, див. Мережева телеметрія в .NET – Події . Але для покращеного журналювання під час процесу EventListener можна використовувати спеціальний параметр, щоб співвіднести пару запит/відповідь із даними підключення:

Крім того, подію Redirect було розширено, щоб включити URI перенаправлення:

-void Redirect();

 

+void Redirect(string redirectUri);

Коди помилок HTTP

Одна з проблем діагностики HttpClient полягала в тому, що у випадку винятку було непросто програмно визначити точну причину помилки. Єдиним способом відрізнити багато з них було розібрати повідомлення про винятки з HttpRequestException. Крім того, інші реалізації HTTP, такі як WinHTTP із кодами помилок ERROR_WINHTTP_*, пропонують такі функції у формі числових кодів або перерахувань. Отже, .NET 8 представляє подібний перелік і надає його у винятках, створених обробкою HTTP, які є:

HttpRequestException для обробки запиту до отримання заголовків відповіді.

HttpIOException для читання змісту відповіді.

Дизайн HttpRequestError enum і те, як він підключається до винятків HTTP, описано в пропозиції API dotnet/runtime#76644 .


Тепер споживач методів HttpClient може обробляти конкретні внутрішні помилки набагато легше та надійніше:

Підтримка проксі HTTPS

Однією з особливо затребуваних функцій, яку було реалізовано в цьому випуску, є підтримка HTTPS-проксі ( dotnet/runtime#31113). Тепер можна використовувати проксі, які обслуговують запити через HTTPS, тобто з’єднання з проксі є безпечним. Це нічого не говорить про сам запит від проксі, який може бути як HTTP, так і HTTPS. У випадку звичайного текстового HTTP-запиту з’єднання з проксі-сервером HTTPS є безпечним (через HTTPS), а потім іде простий текстовий запит від проксі-сервера до пункту призначення. У разі запиту HTTPS (тунель проксі) початковий запит CONNECT на відкриття тунелю буде надіслано через захищений канал (HTTPS) до проксі, а потім запит HTTPS від проксі до пункту призначення через тунель.

 

Щоб скористатися цією функцією, все, що потрібно, це використовувати схему HTTPS під час налаштування проксі:

HttpClientFactory

.NET 8 розширює можливості налаштування HttpClientFactory, включаючи параметри клієнта за замовчуванням, спеціальне логування та спрощену конфігурацію SocketsHttpHandler. API реалізовано в пакеті Microsoft.Extensions.Http, який доступний на NuGet і включає підтримку .NET Standard 2.0. Таким чином, цю функцію можна використовувати клієнтам не лише в .NET 8, але й у всіх версіях .NET, включаючи .NET Framework (єдиним винятком є ​​відповідні API SocketsHttpHandler, які доступні лише для .NET 5+).

Налаштуйте параметри за замовчуванням для всіх клієнтів

.NET 8 додає можливість установити конфігурацію за замовчуванням, яка використовуватиметься для всіх HttpClient-ів створених HttpClientFactory( dotnet/runtime#87914). Це корисно, коли всі або більшість зареєстрованих клієнтів містять однакову підмножину конфігурації.

 

Розглянемо приклад, де визначено два клієнти з іменами, і обидва вони потребують MyAuthHandler для свого ланцюжка обробників повідомлень.

 

Щоб витягти загальну частину, тепер ви можете використовувати метод ConfigureHttpClientDefaults:

Усі методи розширення IHttpClientBuilder, які використовуються з AddHttpClient також можна використовувати всередині .ConfigureHttpClientDefaults.

Конфігурація за замовчуванням (ConfigureHttpClientDefaults) застосовується до всіх клієнтів перед конфігураціями для конкретного клієнта (AddHttpClient); їх відносне положення в реєстрації не має значення. ConfigureHttpClientDefaults можна зареєструвати кілька разів, у цьому випадку конфігурації будуть застосовані одна за одною в порядку реєстрації. Будь-яка частина конфігурації може бути перевизначена або змінена в конфігураціях для конкретного клієнта, наприклад, ви можете встановити додаткові параметри для об’єкта HttpClient або основного обробника, видалити раніше доданий додатковий обробник тощо.

 

Зауважте, що з версії 8.0 метод ConfigureHttpMessageHandlerBuilder застарів . Натомість вам слід використовувати методи ConfigurePrimaryHttpMessageHandler(Action<HttpMessageHandler,IServiceProvider>))) або ConfigureAdditionalHttpMessageHandlers, щоб змінити попередньо налаштований основний обробник або список додаткових обробників відповідно.

Змінити логування HttpClient

Налаштування (або навіть просто вимкнення) логування  HttpClientFactory було однією з давно запитуваних функцій (dotnet/runtime#77312).

Огляд старого логування

Логування за замовчуванням («старе»), додане HttpClientFactory досить багатослівне і видає 8 повідомлень журналу на запит:

1. Почати сповіщення з URI запиту — перед розповсюдженням через конвеєр обробника делегування;

2. Заголовки запитів — перед пайплайном обробника;

3. Почати сповіщення з URI запиту — після пайплайну обробника;

4. Заголовки запитів — після пайплайну обробника;

5. Зупинити сповіщення з вичерпаним часом — перед розповсюдженням відповіді через конвеєр обробника делегування;

6. Заголовки відповіді — перед тим, як передавати відповідь назад;

7. Зупинити сповіщення з вичерпаним часом — після повернення відповіді;

8. Заголовки відповіді — після передачі відповіді назад.

 

Це можна проілюструвати схемою нижче. На цій і наступних діаграмах *і [...]позначає подію логування (у реалізації за замовчуванням повідомлення журналу записується в ILogger), і символізує потік даних через прикладний і транспортний рівні.