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, це дуже багато для написання. Натомість тепер я можу посилатися на тип, що повертається, як CoordinateStream у своїй кодовій базі.

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

 

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

 

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


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


 

Ви помітите, що він повертає псевдонім CoordinateStream, який є IAsyncEnumerable. Він приймає атрибут 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 2. May 2024

Захистіть збірку контейнера та публікуйте за допомогою .NET 8

Захистіть збірку контейнера та публікуйте за допомогою .NET 8


.NET 8 піднімає планку безпеки контейнерів для образів контейнерів .NET та інструментів SDK. За замовчуванням SDK створює образи додатків, які відповідають найкращим галузевим практикам і стандартам. Ми також пропонуємо додаткове посилення безпеки за допомогою образів Chiseled для додаткового рівня захисту.


dotnet publish створить для вас образ контейнера і за замовчуванням налаштує його як non-root. За допомогою .NET дуже просто швидко покращити безпеку ваших виробничих додатків.


У цій статті ви дізнаєтеся, як це зробити:

  • Створення образів non-root контейнерів

  • Налаштуйте Kubernetes, щоб вимагати non-root образи

  • Перевірка образів і контейнерів

  • Використання root  (або інших користувачів)


Ця стаття є продовженням статті Оптимізуйте збірку та публікацію контейнерів за допомогою .NET 8, опублікованої раніше цього місяця. Вона базується на статтях Захистіть свої хмарні додатки .NET за допомогою безкореневих Linux Containers та Запуск non-root контейнерів .NET за допомогою Kubernetes, опублікованих минулого року.


Модель загроз 

Будь-яку розмову про безпеку варто починати з чіткого уявлення про існуючі загрози.


Існує дві основні загрози, які слід враховувати:



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


Це чудовий опис ситуації, від втечі з контейнерів Docker та Kubernetes до root на хості (з посиланням на CVE-2019-5736). Автор говорить, що ми всі разом дуже покладаємося на «налаштування за замовчуванням» різних контейнерних рішень, які ми використовуємо, маючи на увазі, що прорив контейнера є реальною загрозою.


З тієї ж публікації, в розділі «Mitigations»:


Використовуйте низькопривілейованого користувача всередині контейнера


Тут автор фактично говорить про те, що вам потрібно зробити свій внесок, щоб безпечніше покладатися на псевдо-пісочницю контейнерних рішень. Якщо ви цього не зробите, і буде виявлено чергову вразливість контейнерів, то частина тягаря ляже на розробників, які розміщують свої додатки з правами root. Інакше кажучи, «caveat emptor».


У ландшафті безпеки та вразливостей може бути важко орієнтуватися навіть у найкращі часи. Актуалізація залежностей – це перший і найважливіший спосіб зменшити ці ризики, як для хоста, так і для гостя контейнера. Non-root хостинг є чудовим заходом глибокого захисту, який може захистити від невідомих майбутніх вразливостей.

Контейнерна екосистема: root за замовчуванням

 

Базові образи за замовчуванням налаштовано під користувачем root .

Після того, як я пояснив, що образи слід налаштовувати як non-root як важливий захід безпеки, я демонструю, що більшість базових образів публікуються з правами root, в тому числі і ті, які публікуємо ми. Чому?


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


Однак, залишається вірним, що зловмисник з активною RCE-уразливістю зможе робити все, що завгодно, маючи привілеї root.


На відміну від них, базові образи Ubuntu Chiseled і Chainguard орієнтовані на пристрої і використовують інший підхід, ніж образи загального призначення. Вони обмінюють зручність використання і сумісність на безпеку. Ми підтримуємо цю точку зору.


Примітка: див. Образи захищених контейнерів: Зображення для безпечного ланцюга постачання.


Це багато контексту про базові образи і відмінний перехід до образів додатків, які (на нашу думку) повинні бути побудовані з філософією безпеки в першу чергу.

.NET екосистеми: Non-root за замовчуванням

За замовчуванням dotnet publish створює образи без права доступу до кореневого каталогу. Давайте подивимося на це за допомогою простої консольної програми. Я пропущу ряд кроків, які описано у статті Спрощення збірки контейнера та публікації за допомогою .NET 8.


Це вихідний код програми.

Створити зображення контейнера дуже просто.

 

 

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

 

Як і очікувалося, ми бачимо Hello app.


Ми також можемо запустити whoami так само, як це було зроблено з базовими зображеннями.

 

Як видно, цей образ не використовує root, на відміну від базових образів, які ми розглянули.


Запуск whoami вимагає запуску образу. Kubernetes не робить цього; він дивиться на метадані зображення контейнера, щоб визначити користувача.


Давайте подивимося на метадані контейнера.

 


SDK встановлює користувача за допомогою UID, оскільки це вимагається Kubernetes для застосування властивості runAsNonRoot.


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

 

 

Ми визначаємо користувача з ім’ям app і даємо йому UID > 1000, щоб уникнути зарезервованих діапазонів. 1654 - це 1000  + ASCII-значення кожного з символів у dotnet. Ми також встановлюємо змінну оточення – APP_UID – з таким самим значенням. Це дозволяє уникнути необхідності запам’ятовувати або використовувати це значення (без змінної оточення) для звичайних сценаріїв.


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

Non-root Dockerfiles

Модель з Dockerfiles схожа, але вимагає одного додаткового кроку – встановлення інструкції USER .


Я покажу вам, як це виглядає, використовуючи цей приклад Dockerfile.


Цей Dockerfile використовує змінну оточення, яку ми щойно розглянули, для визначення користувача. Це шаблон, який ми хочемо, щоб усі використовували для переходу до користувача без прав суперкористувача за допомогою Dockerfiles. Знову ж таки, цей шаблон дозволяє уникнути повсюдного використання магічних чисел і найкраще працює у Kubernetes.

Примітка: Багато розробників вже створили власного користувача. Продовження роботи з власним користувачем або перемикання на вбудованого – обидва варіанти є чудовими.


Після цього ми можемо створити і запустити образ.

 

 

Як бачите, програма працює від імені користувача app.

Перемикач для увімкнення non-root  хостингу (у Dockerfiles) – це лише зміна одного рядка.

Ubuntu Chiseled образи

Образи Ubuntu Chiseled схожі на пристрої, що надають заблокований досвід роботи за замовчуванням. Вони сумісні зі звичайною Ubuntu, проте мають гострі краї, де вирізані цілі розділи операційної системи. Примітно, що вони налаштовані як non-root. Це означає, що вам навіть не потрібно налаштовувати користувача, оскільки він вже налаштований.


Ви можете оглянути вирізане зображення, щоб переконатися, що користувач налаштований.

 

 

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

 

Як ви можете бачити, у цьому Dockerfile не задано USER. Давайте зберемо і запустимо його.

 

Знову ж таки, додаток запускається від імені користувача app. Якщо ви використовуєте чисельні зображення, ви отримуєте кращі результати і менше роботи у вашому Dockerfile.


Ви можете так само легко використовувати Chiseled images за допомогою SDK publish.

 

 

Ця команда створить non-root образ, оскільки наші Chiseled images налаштовані як non-root , а dotnet publish створює non-root образи за замовчуванням.


Kubernetes

Kubernetes має механізм runAsNonRoot, який є частиною стандартів безпеки. Якщо цей параметр встановлено у true, Kubernetes не зможе завантажити маніфест пакунків, якщо образ контейнера має права root.


Я вважаю runAsNonRoot функцією типу «ролі та обов’язки». Роль образу контейнера визначає користувач. Відповідальність оркестратора полягає у перевірці того, що користувач встановлений як очікується, як non-root.


Згадайте погляд на метадані контейнера «як це робиться у Kubernetes», який ми розглядали раніше.

 

Kubernetes не використовує docker inspect, але ідея та сама. Він дивиться на те саме значення User, визначає, чи є це значення UID, і якщо так, то перевіряє value > 0. Якщо цей вираз дорівнює true, то проходить перевірка runAsNonRoot. У контексті root має UID 0, тому ця перевірка є аналогом user != root.


Давайте швидко розглянемо, як працює non-root у Kubernetes. Якщо ви хочете дізнатися більше, читайте статтю Запуск non-root .NET контейнерів у Kubernetes.


Ось приклад того, як задати runAsNonRoot у маніфесті Pod

У цьому прикладі кожен перелічений контейнер (навіть якщо у прикладі лише один) має бути non-root. securityContext також може бути задано для контейнера. Ви можете переглянути ці налаштування у ширшому контексті у файлі non-root.yaml.


Насправді цікаво подивитися, що станеться, якщо runAsNonRoot буде встановлено у true і ми спробуємо завантажити образ, який використовує користувачів  root.


На момент написання статті образ mcr.microsoft.com/dotnet/samples:aspnetapp-chiseled (використаний вище) налаштовано як non-root, а  mcr.microsoft.com/dotnet/samples:aspnetapp - як root. Я зміню значення image в маніфесті на mcr.microsoft.com/dotnet/samples:aspnetapp, а потім подивлюся, чи не відбудеться збій при завантаженні.

Як бачите, навантаження не проходить.

 

Якщо копнути трохи глибше, то можна зрозуміти причину.

Це відповідає очікуванням. Добре.

Змініть користувача на root

Бувають випадки, коли користувачеві потрібно встановити права користувача root. Зробити це дуже просто.


Можна (за допомогою Docker) запустити команду від імені користувача root у запущеному контейнері за допомогою docker exec -u. Найчастіше це буде команда bash, але ми будемо використовувати whoami, оскільки вона пропонує кращу демонстрацію.

 

Зверніть увагу, що kubectl exec не пропонує аргумент -u (з поважної причини).


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

 

Нарешті, конкретний користувач може бути використаний при створенні образу за допомогою ContainerUser.

Вказаний ContainerUser  повинен існувати.

 

Однак ви можете використовувати дійсний UID.

 

Як ви можете бачити, у зображеннях контейнерів, які ми публікуємо, визначені як користувач root, так і користувач app.

Закриття

Користувач для виробничих програм є ключовою частиною будь-якого плану безпеки. На жаль, його легко пропустити, оскільки все працює без вказівки користувача. Насправді, все працює занадто добре. Можна сказати, що це і є корінь проблеми.


Додати користувача до Dockerfile дуже просто. Створити наскрізні робочі процеси, які надійно встановлюють бажані результати безпеки, набагато складніше. Як бачите, тепер легко створювати non-root образи контейнерів за допомогою dotnet publish або Dockerfiles. Образи будуть коректно працювати з функціями безпеки Kubernetes, що є критично важливим для забезпечення бажаних політик безпеки.


Завжди будуть потрібні додаткові налаштування безпеки. Non-root хостинг – це одна з найвпливовіших змін, яку ви можете зробити.



Posted on 30. April 2024

Подорож до доступних програм: доступність клавіатури та .NET MAUI

Подорож до доступних програм: 

доступність клавіатури та .NET MAUI


Чи доступна клавіатура ваших додатків? Давайте перевіримо:


  1. Запустіть одну з ваших програм.

  2. Підключіть фізичну клавіатуру, якщо вона ще не підключена до вашого пристрою.

  3. Переміщайтеся у програмі так, як ви зазвичай це робите, і використовуйте для цього лише клавіатуру.

Як вам це вдалося? Чи було легко? Чи збігається це з вашим звичним досвідом навігації у додатку?


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

Настанови з доступності веб-контенту (WCAG)

Щоб зрозуміти, що саме являє собою клавіатурна доступність, варто почати з Керівництва з доступності веб-контенту (WCAG).


WCAG – це набір технічних стандартів веб-доступності, на який часто посилаються і який поширюється на різні додатки та платформи за межами Інтернету. Він став глобальним стандартом і правовим орієнтиром і продовжує розвиватися разом з мінливим ландшафтом технологій.


Серед різних настанов є Guideline 2.1, яку часто не беруть до уваги, в якій йдеться про те, що розробники повинні «Зробити всю функціональність доступною з клавіатури».


Це включає в себе чотири критерії успіху:

Критерій успіху 2.1.1 Клавіатура

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

Критерій успіху 2.1.2 Відсутність пастки клавіатури

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

Критерій успіху 2.1.3 Клавіатура (без винятків)

Вся функціональність контенту доступна через клавіатурний інтерфейс, не вимагаючи спеціального часу для окремих натискань клавіш.

Критерій успіху 2.1.4 Символьні комбінації клавіш

Якщо комбінація клавіш реалізована у контенті з використанням лише літер (включаючи великі та малі літери), розділових знаків, цифр або символів, то принаймні одна з наведених нижче ознак є істинною:


Вимкнути Існує механізм для вимкнення комбінації клавіш;

Змінити комбінацію клавіш Існує механізм для зміни комбінації клавіш, щоб додати до неї одну або кілька недрукованих клавіш клавіатури (наприклад, Ctrl, Alt);

Активна лише у фокусі Комбінація клавіш для компонента користувацького інтерфейсу активна лише тоді, коли на цьому компоненті є фокус.


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

Доступ до клавіатури та .NET MAUI

Окрім інших міркувань, .NET MAUI було розроблено з метою полегшити розробку клавіатурного інтерфейсу. Отже, розробники, знайомі з поведінкою клавіатури Xamarin.Forms, помітили деякі зміни, які були зроблені для покращення доступності клавіатури в їхніх додатках.


Для того, щоб вся функціональність працювала через клавіатурний інтерфейс, важливо, щоб всі інтерактивні елементи управління були клавіатурно орієнтованими (могли отримувати фокус клавіатури) і клавіатурно навігаційними (могли переходити до них і з них за допомогою клавіатури). Це також включає в себе уникнення того, щоб невидимий вміст був доступний за допомогою клавіатури. Так само, як ми повинні очікувати, що видимі елементи керування будуть доступними для клавіатурного фокусу та навігації, ми повинні очікувати, що невидимі/неіснуючі елементи керування не будуть доступними для клавіатури або взагалі не будуть присутніми.


Щоб уникнути клавіатурних пасток, ми гарантуємо, що клавіатурна навігація можлива до всіх відповідних елементів керування у поточному поданні, всередині них та поза ними. Наприклад, якщо ви переміщуєтесь по екрану з декількома CollectionViews, .NET MAUI узгоджується зі стандартними очікуваннями клавіатурної доступності, дозволяючи вам легко переходити до будь-якого з CollectionViews та з нього за допомогою стандартних шаблонів клавіатурної навігації.


Тож як саме .NET MAUI дозволяє вам створювати клавіатурні інтерфейси з більшою легкістю? Ось 3 приклади:

1. Клавіатурна навігація на модальних сторінках

Однією з областей, в якій .NET MAUI навмисно враховує доступність клавіатури, є модальні сторінки. Коли з’являється модальна сторінка, як і для всіх інших сторінок, важливо переконатися, що все на ній доступно. Однак для модальних сторінок особливо важливо переконатися, що все, що знаходиться на основній сторінці, не доступне з клавіатури і не з’являється на модальній сторінці.


Коли з’являється модальна сторінка, фокус має бути на першому клавіатурному елементі керування на сторінці. Після цього весь вміст модальної сторінки має бути доступним, а всі інтерактивні елементи керування, які мають містити опцію виходу (зазвичай «Зберегти» або «Закрити») з модальної сторінки, мають бути сфокусовані на клавіатурі. Після виходу з модальної сторінки фокус має бути повернутий на основну сторінку, і перший елемент керування на основній сторінці повинен знову отримати фокус на клавіатурі.


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

2. Фокусування/розфокусування клавіатури на Android

Під час розробки .NET MAUI ми дізналися ще одну річ, що неможливо «розфокусувати» запис на ранніх версіях Android. Якийсь елемент управління завжди повинен бути сфокусований. У Xamarin.Forms «розфокусувати» елемент можна було, встановивши фокус на макеті сторінки; на жаль, такий підхід створював серйозні проблеми з доступністю. З цих причин .NET MAUI не дозволяє таку недоступну поведінку за замовчуванням і наполегливо рекомендує використовувати інший підхід.


Мотивація використання «фокусування» і «розфокусування» часто пов’язана з показом і приховуванням клавіатури м’якого введення. Замість того, щоб маніпулювати фокусом для досягнення цієї мети, керуйте поведінкою клавіатури за допомогою нових SoftInputExtensions APIs

 

Наприклад:

Якщо SoftInputExtensions або інші альтернативні рішення не працюють для ваших потреб у фокусуванні клавіатури, команда .NET MAUI буде рада дізнатися більше про ваш сценарій. Будь ласка, поділіться з нами, щоб ми могли краще зрозуміти ваші потреби в розробці!


З огляду на це, у .NET 8 було введено додаткову властивість HideSoftInputOnTapped. Застосування цієї властивості дозволяє користувачам натискати на сторінку, щоб приховати клавіатуру м’якого введення, і ми рекомендуємо використовувати її лише у виняткових випадках.


3. Прискорювачі клавіатури

Як і у випадку з усіма чудовими, доступними рішеннями, проектування з урахуванням доступності означає проектування для всіх. Це особливо стосується доступності клавіатури, де ввімкнення витонченої поведінки клавіатури приносить користь усім користувачам, від тих, хто використовує клавіатуру як основний режим введення, до досвідчених користувачів, які полюбляють використовувати клавіатурні скорочення, також відомі як клавіатурні прискорювачі.


У .NET MAUI ми створили рішення для клавіатурних прискорювачів. За допомогою клавіатурних прискорювачів усі користувачі клавіатури та робочого столу можуть використовувати комбінації клавіш для активації команд пунктів меню!

 

Як описано в документації .NET MAUI, ось як можна почати додавати клавіатурні прискорювачі до MenuFlyoutItem в XAML або C#:

Обов’язково включіть клавіатурні прискорювачі у свій додаток .NET MAUI, якщо ви цього ще не зробили, і застосуйте свої нові знання з Критерію Успіху WCAG 2.1.4!

Подорож до доступних додатків

З інтерфейсом .NET MAUI ви можете створювати додатки, повністю доступні з клавіатури і позбавлені клавіатурних пасток, і зробити це простіше, ніж будь-коли раніше.


Якщо ви вперше читаєте «Подорож до доступних додатків», ласкаво просимо! Не забудьте переглянути мої попередні публікації в блозі, щоб дізнатися більше про створення доступних додатків і про те, як .NET MAUI полегшує цей процес.


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


.NET MAUI допомагає вам створювати доступні програми простіше, ніж будь-коли раніше. Як завжди, дайте нам знати, як ми можемо зробити це ще простіше для вас!




Posted on 28. April 2024

Представляємо вам .NET MAUI Community Tookit v8: з'явилася підтримка TouchBehavior!

Представляємо вам .NET MAUI Community Tookit v8: з’явилася підтримка TouchBehavior!


Команда .NET MAUI Community Toolkit з гордістю представляє вам 8 версію інструментарію .NET MAUI Community Toolkit!


У цьому останньому великому випуску ми представили довгоочікувану TouchBehavior (раніше відому як TouchEffect). Але також, остерігайтеся змін у Snackbar у Windows, і чи знаєте ви, що ви можете розфарбувати навігаційну панель Android?


TouchBehavior

Якщо ви використовували Xamarin Community Toolkit у вашому додатку Xamarin.Forms, ви, ймовірно, знаєте про TouchEffect. Починаючи з .NET MAUI, ефекти були застарілими і їх слід перенести до (Platform)Behaviors. Це саме те, що ми зробили для цієї функціональності, реалізувавши її для .NET MAUI.


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

 

 

Величезне спасибі Олександру, також відомому як Axemasta, члену спільноти, який тісно співпрацював з нами над цим проектом. Він проробив дивовижну роботу, щоб реалізувати цю величезну функцію, на яку багато людей чекали. Величезне йому спасибі!


Функція не є повною без документації, тому ми також підготували її для вас. Зверніть увагу, що є деякі зміни порівняно з TouchEffect для Xamarin, тому ми додали розділ, який допоможе вам з міграцією.


(Breaking) зміни в Behaviors

Під час роботи над TouchBehavior ми виявили, що контекст прив’язки застосовувався неправильно. Хороша новина полягає в тому, що ми знайшли причину цього, погана новина полягає в тому, що це стосувалося не тільки TouchBehavior, але й усіх інших поведінок у Toolkit.


На щастя, Брендон швидко знайшов першопричину і надав виправлення, яке ми невдовзі випустили.


Технічно, це зміна, яка порушує семантичну схему версій, але ми вирішили, що це не вплине на велику кількість людей. Якщо ми помилилися, приносимо свої вибачення і просимо зв’язатися з нами, щоб ми могли допомогти вам розібратися. Будь ласка, зробіть це, відкривши питання у сховищі з усіма необхідними деталями.


Breaking зміни для Snackbar у Windows

Нова велика версія зазвичай означає нові цікаві можливості, але також і докорінні зміни. У цьому випадку є кілька докорінних змін для використання Snackbar у Windows.


Власне, Владислав повністю переписав реалізацію Snackbar у Windows. Цими змінами ми замінили те, що використовується під капотом для реалізації Snackbar і Toast у Windows. В результаті ми виправили деякі збої, але, що більш важливо, ваш додаток для Windows більше не запускатиме інший екземпляр при взаємодії з Toast або Snackbar.


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


Колір навігаційної панелі Android

Перш ніж ми перейдемо до цієї нової функції, давайте спочатку прояснимо, про що саме ми говоримо. Термін «панель навігації», здається, викликає деяку плутанину. Зазвичай, коли люди думають про панель навігації, вони мають на увазі панель у верхній частині сторінки з заголовком і, можливо, деякими елементами панелі інструментів. Однак, в контексті Android існує також системна панель навігації. Це та, що має 3 кнопки для повернення на попередню сторінку, відкриття багатозадачного режиму і переходу на головний екран вашого пристрою. Саме про цю навігаційну панель ми зараз говоримо!


Маючи це на увазі, давайте поговоримо про саму функцію. Тепер ви можете розфарбувати цю панель на Android так, щоб ваш додаток виглядав ще більш захоплююче, а ваша тема повністю інтегрувалася з усім, що ви бачите на екрані.



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


Як почати роботу і все, що вам потрібно знати про цю функцію, можна знайти в документації.


Багато виправлень та оптимізацій

Звичайно, у цьому випуску було виконано багато іншої роботи, не забудьте переглянути повний список у примітках до випуску з усіма виправленнями та іншими оптимізаціями, які було зроблено у цьому випуску.


Велике спасибі всім, хто зробив цей випуск можливим, особливо всім учасникам спільноти, які так люб’язно витратили свій дорогоцінний час на наш проект і внесли свій вклад в екосистему .NET MAUI.

Що далі?

Ми раді представити вам останню велику версію .NET MAUI Community Toolkit, але, звичайно, ми не зупиняємося на досягнутому. Над наступною важливою функцією вже ведеться робота – CameraView, яка зараз переноситься з Xamarin на .NET MAUI. Хоча це частина сімейства Toolkit, він буде випущений окремим пакетом, тому слідкуйте за його появою. Крім того, ми працюємо над покращенням MediaElement, щоб забезпечити глибшу інтеграцію з операційною системою, наприклад, відтворення медіа з екрану блокування та відображення відповідних метаданих, і, звісно, багато іншого.


Повідомте нам, що ви думаєте про цей останній випуск, зв’яжіться з нами через GitHub repository, приєднайтеся до нашого Discord server і приходьте на наші прямі трансляції, які відбуваються кожного першого четверга місяця на  .NET Foundation YouTube channel  о 12:00 за тихоокеанським часом.

 

Ви можете отримати все це добро вже сьогодні! Отже, не забудьте оновити свій пакет .NET MAUI Community Toolkit до версії 8 сьогодні і починайте кодувати!



Posted on 5. April 2024

Transform your business with smart .NET apps powered by Azure and ChatGPT

Трансформуйте свій бізнес за допомогою розумних .NET-додатків на базі Azure та ChatGPT


За допомогою ChatGPT ви можете розкрити весь потенціал штучного інтелекту у своїх програмах .NET і гарантувати неймовірний досвід для користувачів від використання природної мови. ChatGPT — це більше, ніж просто інструмент; це те, що кардинально змінює те, як ми отримуємо доступ до даних і аналізуємо їх. Незалежно від того, використовуєте ви Azure, SQL Server або будь-яке інше джерело даних, ви можете легко інтегрувати ChatGPT у свої проєкти .NET і почати створювати інтелектуальні програми вже сьогодні.


У цій публікації я дам короткий огляд того, що таке інтелектуальні програми. Потім, використовуючи зразок програми, я покажу, як за допомогою комбінації служб Azure, таких як Azure OpenAI Service і Azure Cognitive Search, ви можете створювати власні інтелектуальні програми .NET.

TLDR

Ви найкраще вчитеся на практичному досвіді? Ознайомтеся з репозиторієм і приступайте прямо зараз!

Створіть свій власний розумний додаток .NET

Що таке розумні програми?

Розумні програми — це програми на основі штучного інтелекту, які змінюють продуктивність користувачів, автоматизують процеси та дають змогу отримувати різну інформацію.


Bing Chat є прикладом інтелектуальної програми.

Зображення розмови Bing Chat про рецепти


ШІ лежить в основі Bing Chat. Bing Chat використовує штучний інтелект для обробки складних запитів, узагальнення релевантної інформації з різних джерел і створення відповідей.


Створюйте інтелектуальні програми за допомогою .NET

Тепер, коли ви маєте уявлення про те, що таке інтелектуальні програми, давайте подивимося на приклад програми, створеної за допомогою .NET, Azure і ChatGPT.


Переглянути відео


Припустімо, у вас є внутрішня корпоративна база знань, яка містить інформацію про посади, плани охорони здоров’я та інші ділові документи.


Можливо, ваші користувачі вже можуть здійснювати пошук у цій базі знань, але пошук відповідей на конкретні запитання шляхом фільтрування всіх документів у результатах пошуку може зайняти багато часу.

Використовуючи моделі штучного інтелекту, такі як ChatGPT, ви можете змінити продуктивність своїх користувачів, узагальнюючи інформацію, що міститься в цих документах, формуючи ключові висновки.


Архітектура програми

Вихідний код програми знаходиться на GitHub. Нижче наведено основні компоненти програми.

Інтерфейс користувача

Інтерфейс програми є статичною веб-програмою Blazor WebAssembly . Цей інтерфейс приймає запити користувачів, направляє запити до серверної частини програми та відображає згенеровані відповіді. Якщо ви працюєте з клієнтськими програмами на мобільному телефоні чи настільному комп’ютері, .NET MAUI також буде хорошим варіантом для цього компонента.

Сервер програми

Бекенд програми — це мінімальний API ASP.NET Core . Серверна частина містить статичну веб-програму Blazor і те, що організовує взаємодію між різними службами. Послуги, які використовуються в цій програмі, включають:


– Azure Cognitive Search – індексує документи з даних, що зберігаються в обліковому записі Azure Storage. Це робить документи доступними для пошуку.


– Служба Azure OpenAI – надає моделі ChatGPT для створення відповідей. Крім того, Semantic Kernel використовується в поєднанні зі службою Azure OpenAI Service для організації більш складних робочих процесів ШІ.


Azure Redis Cache – кешує відповіді. Це зменшує затримку під час створення відповідей на схожі запитання та допомагає керувати витратами, оскільки вам не потрібно робити інший запит до служби Azure OpenAI.


Надання ресурсів і середовища для розробника

З усіма згаданими послугами процес початкового налаштування може здатися складним. Однак ми спростили цей процес за допомогою Azure Developer CLI . Якщо ви не хочете встановлювати будь-яку залежність, ми також можемо вам допомогти. Просто відкрийте репозиторій у GitHub Codespaces і використовуйте Azure Developer CLI, щоб надати свої послуги.


Використання ChatGPT у ваших документах

Тепер, коли ви знаєте компоненти, з яких складається ця програма, давайте подивимося, як вони працюють разом у контексті чату.


Перш ніж почати спілкуватися в чаті зі своїми документами, ви захочете мати базу знань, до якої можна зробити запит. Швидше за все, у вас вона вже є. Для цього прикладу програми ми зробили просту базу знань. У каталозі даних програми є набір PDF-документів. Щоб завантажити їх у Azure Storage та індексувати в Azure Cognitive Search, ми створили консольну програму C#.



Консольна програма C# виконує такі дії:

1. Використовує Azure Form Recognizer для вилучення тексту з кожного документа.

2. Розбиває документи на менші уривки. (нарізка)

3. Створює новий документ PDF для кожного з уривків.

4. Завантажує уривок до облікового запису сховища Azure.

5. Створює індекс у Azure Cognitive Search.

6. Додає документи до індексу когнітивного пошуку Azure.

 

Чому PDF-файли розбиваються на частини?


Моделі OpenAI, такі як ChatGPT, мають обмеження на токени. Щоб отримати додаткові відомості про обмеження маркерів, перегляньте довідковий посібник із квот і обмежень служби Azure OpenAI.


У цьому прикладі процес створення бази знань є ручним. Однак, залежно від ваших потреб, ви можете запускати його як завдання на основі подій щоразу, коли новий документ додається до облікового запису Azure Storage, або пакетно як фонове завдання.


Ще один шаблон, про який варто згадати, передбачає використання вбудовування для кодування семантичної інформації про ваші дані. Ці вбудовування зазвичай зберігаються у векторних базах даних. Щоб отримати коротку інформацію про вбудовування, перегляньте документацію щодо вбудовування Azure OpenAI . Цей шаблон не є основним, що використовується в цьому прикладі, і виходить за рамки цієї публікації. Однак у наступних публікаціях ми розглянемо ці теми більш детально, тож слідкуйте за оновленнями!


Спілкуйтеся зі своїми даними

Коли ви налаштуєте свою базу знань, настав час поспілкуватися з нею.


Зображення запитання, яке ставлять у веб-програмі ChatGPT .NET

Запит до бази знань починається з того, що користувач вводить запитання у веб-програмі Blazor. Потім запит користувача направляється до ASP.NET Core Minimal Web API.


Всередині веб-інтерфейсу API кінцева точка chat обробляє запит.

api.MapPost(“chat”, OnPostChatAsync);

Щоб обробити запит, ми застосовуємо шаблон, відомий як Retrieval Augmented Generation, який робить наступне:

1. Запитує в базі знань відповідні документи

2. Використовує відповідні документи як контекст для створення відповіді


Запит до бази знань


Запити до Бази знань відбуваються за допомогою когнітивного пошуку Azure. Хоча когнітивний пошук Azure не розуміє природну мову, надану користувачем. На щастя, ми можемо використовувати ChatGPT, щоб допомогти перекласти природну мову в запит.

 

Використовуючи семантичне ядро, ми створюємо метод, який визначає шаблон підказки та додає історію чату та запитання користувача як додатковий контекст для створення запиту Azure Cognitive Search.

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

Коли ви запускаєте функцію семантичного ядра, вона надає складену команду моделі Azure OpenAI Service ChatGPT, яка генерує відповідь.

З огляду на питання “Що входить до мого плану Northwind Health Plus, чого немає в стандарті?”, сформований запит може виглядати так: “Покриття плану Northwind Health Plus


Після створення запиту скористайтеся клієнтом Azure Cognitive Search, щоб зробити запит до індексу, що містить ваші документи.

На цьому етапі когнітивний пошук Azure поверне результати, які містять документи, які найбільше відповідають вашому запиту. Результати можуть виглядати так:


Northwind_Health_Plus_Benefits_Details-108.pdf: ви повинні надати Northwind Health Plus з копією EOB для первинного страхування, а також копію заяви, яку ви подали до свого первинного страхування. Це дозволить нам визначити переваги, доступні вам за Northwind Health Plus. Важливо зазначити, що Northwind Health Plus не покриває жодних витрат, які вважаються відповідальністю Основного покриття.

Benefit_Options-3.pdf: Плани також охоплюють профілактичні послуги, такі як мамографія, колоноскопія та інші скринінги на рак. Northwind Health Plus пропонує більш повне покриття, ніж Northwind Standard. Цей план пропонує покриття екстрених служб, як у мережі, так і поза мережею, а також покриття психічного здоров’я та зловживання психоактивними речовинами. Northwind Standard не пропонує покриття послуг екстреної допомоги, психічного здоров’я та токсикоманія, а також послуги поза мережею

Створення відповіді

Тепер, коли у вас є документи з відповідною інформацією, яка допоможе відповісти на запитання користувача, настав час використати їх для створення відповіді.


Ми починаємо з використання семантичного ядра для створення функції, яка створює запит, що містить історію чату, документи та додаткові запитання.