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 не пропонує покриття послуг екстреної допомоги, психічного здоров’я та токсикоманія, а також послуги поза мережею

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

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


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

Чи жорстко ми кодуємо відповіді в запиті?


НЕ жорстко. Приклади в запиті слугують вказівками для моделі для створення відповіді. Відоме як кількакратне навчання.

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


Після деякого форматування відповідь повертається до веб-програми та відображається. Результат може виглядати приблизно так:


Зображення, на якому показано відповіді, згенеровані ChatGPT у веб-програмі .NET

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

Створюйте власні інтелектуальні програми

Ми з нетерпінням чекаємо майбутнього інтелектуальних програм у .NET.

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

 

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


 

Source




Posted on 16. March 2024

Get started with .NET 8 and AI using new quickstart tutorials

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

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

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

Ми щойно випустили новий набір швидких запусків, які ви можете використовувати з великими мовними моделями OpenAI (незабаром з'явиться ще більше моделей):

У кожному прикладі ви крок за кроком ознайомитеся з кодом, необхідним для виконання теми, за допомогою Azure OpenAI SDK. Дуже скоро ми також додамо версії цих прикладів з використанням Semantic Kernel SDK (ми опублікуємо пост тут, коли вони будуть готові).

Дізнайтеся більше про основні концепції

Якщо ChatGPT, LLM, моделі та OpenAI - це нові для вас терміни, або ви тільки починаєте працювати в цій сфері, ось кілька додаткових ресурсів, які допоможуть вам вивчити основні поняття та дослідити їх краще:

 



.NET | AI | C#
Posted on 9. December 2023

Learn .NET 8 with New Beginner Videos

Вивчайте .NET 8 з новими відео для початківців

Дивіться серію статей про .NET 8 для початківців


Новачок у .NET? Приєднуйтесь до нас і дивіться нову серію .NET 8 для початківців, щоб зрозуміти .NET крок за кроком. Ми щойно запустили дев'ять нових серій для початківців про C#, .NET, генеративний ШІ, NuGet, Visual Studio, VS Code та C# Dev Kit, Blazor Hybrid, .NET IoT та модернізацію .NET додатків. Ми розповімо про те, що таке .NET, що ви можете створювати з його допомогою, як почати роботу з професійними інструментами та поради щодо покращення ваших проектів.  


Нижче наведено огляд кожної нової серії.


Вивчайте C# від експертів  

Приєднуйтесь до Скотта Хансельмана та видатного інженера .NET Девіда Фаулера, які навчають нас C# з нуля. Від Hello World до LINQ і не тільки, Скотт і Девід ділитимуться уроками C# у глибокому та неквапливому темпі. Наприкінці ви будете готові до вивчення базової сертифікації C# від FreeCodeCamp!  

Дивіться на YouTube


Переглянути на Microsoft Learn


Генеративний ШІ з .NET для початківців   

Пориньте з головою в майбутнє, щоб дізнатися про безперешкодну інтеграцію штучного інтелекту (AI) і машинного навчання (ML) у ваші програми .NET, що відкриває перед вами безліч можливостей. Від розуміння основних концепцій до практичних занять з ChatGPT, Azure AI Services та ML.NET ви отримаєте навички створення інтелектуальних, адаптивних додатків. Приєднуйтесь до нас у цій подорожі та зробіть революцію у своїх .NET-додатках, використовуючи безмежний потенціал .NET, штучного інтелекту та хмарних розробок!


Дивіться на YouTube  


Переглянути на Microsoft Learn


.NET  

Не знайомі з .NET? Ми знаємо, що вам ще багато чого треба вивчити - тож приєднуйтесь до нас у серії .NET для початківців, щоб зрозуміти .NET крок за кроком. Ми розповімо про те, що таке .NET, що ви можете створювати з його допомогою, як розпочати роботу з VS Code та як покращити ваші проекти за допомогою пакетів NuGet.

  

Дивіться на YouTube  


Переглянути на Microsoft Learn


Azure для .NET розробників  

Курс .NET на Azure для початківців навчить вас основам Azure та використанню її сервісів і функцій для створення чудових хмарних додатків. Ви дізнаєтеся, як розгортати веб-додатки, працювати зі сховищем і даними, автентифікуватись і використовувати керовану ідентичність, використовувати можливості контейнерів і навіть розгортати за допомогою GitHub Actions. Наприкінці цього курсу ви матимете навички та впевненість, щоб почати розробляти власні .NET-додатки в Azure!

Дивіться на YouTube


Розробка на C# та .NET за допомогою Visual Studio  

Visual Studio - це інтегроване середовище розробки (IDE), яке є дуже популярним для робочих навантажень .NET та C++. У цій серії статей ми коротко розглянемо найкращі можливості Visual Studio, включаючи навігацію кодом, налагодження, тестування, завершення коду та спільну роботу. Ви дізнаєтесь все необхідне для початку роботи з Visual Studio 2022 та .NET 8, а також отримаєте багато цінних порад щодо кастомізації та підвищення продуктивності.  


Дивіться на YouTube


Переглянути на Microsoft Learn


Розробка C# та .NET за допомогою VS Code  

Писати C# додатки у Visual Studio Code ще ніколи не було так просто! Нещодавно ми представили нове розширення C# Dev Kit У цій серії відео ви дізнаєтеся, як почати писати, налагоджувати, тестувати і продуктивно запускати свої C# додатки у VS Code за допомогою нового розширення C# Dev Kit.

 

Дивіться на YouTube


Переглянути на Microsoft Learn


Керування пакетами .NET за допомогою NuGet  

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

Дивіться на YouTube


Переглянути на Microsoft Learn


Blazor Hybrid   

Приєднуйтесь до Джеймса Монтемагно (James Montemagno), який проведе вас у подорож по створенню ваших перших гібридних додатків для iOS, Android, Mac, Windows та Web за допомогою ASP.NET Core, Blazor, Blazor Hybrid та .NET MAUI! Ви дізнаєтесь, як використовувати Blazor Hybrid для поєднання нативних клієнтських фреймворків для настільних та мобільних пристроїв з .NET та Blazor.

Дивіться на YouTube  


Переглянути на Microsoft Learn


.NET IoT  

Оскільки .NET є кросплатформенною і працює на різних архітектурах процесорів, вона сумісна з широким спектром одноплатних комп'ютерів, включаючи Raspberry Pi. Ці пристрої широко використовуються в сценаріях Інтернету речей (IoT) для зв'язку з датчиками, дисплеями, аналого-цифровими перетворювачами тощо. У цій серії ви дізнаєтесь про основи запуску коду .NET на одноплатних комп'ютерах та ефективне використання бібліотек .NET IoT для зв'язку з різними пристроями Інтернету речей. Ви також побачите різні практичні приклади, які надихнуть вас на створення власних проектів! 

Дивіться на YouTube 


Переглянути на Microsoft Learn


Оновлення додатків за допомогою .NET  

Щороку виходять нові версії .NET, і тепер дуже легко перейти на найновішу версію, незалежно від того, який цільовий фреймворк .NET ви зараз використовуєте. У цій серії статей ви дізнаєтеся, як оновити свої програми до найновішої версії .NET за допомогою існуючих інструментів від Microsoft. Ми розглянемо оновлення для різних типів додатків, використовуючи як розширення Visual Studio, так і інструмент CLI. 

Дивіться на YouTube 

 

Переглянути на Microsoft Learn

 

 



Posted on 17. November 2023

Announcing C# 12

Анонс C# 12

C# 12 доступний вже сьогодні! Ви можете отримати його, завантаживши .NET 8, останню версію Visual Studio або C# Dev Kit від Visual Studio Code.


Для існуючих проектів вам також потрібно вказати, що ви хочете змінити мовну версію. Ви можете змінити мовну версію, змінивши TargetFramework на .NET 8:

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


Спрощення коду

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


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

Вирази колекцій

 

До C# 12 створення колекцій вимагало різного синтаксису для різних сценаріїв. Ініціалізація List<int> вимагала іншого синтаксису, ніж int[] або Span<int>. Ось лише декілька способів створення колекцій:

Вирази колекцій мають уніфікований синтаксис:

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


А якщо цього виявиться недостатньо - ви можете використовувати оператор new spread для включення елементів однієї або декількох колекцій або перечислювальних виразів у вираз колекції:

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


Ми дуже зацікавлені у відгуках щодо можливої майбутньої роботи над виразами колекцій. Ми розглядаємо можливість розширення виразів колекцій за рахунок словників та підтримки var (природних типів) у майбутній версії C#.


Як і багато інших нових можливостей C#, аналізатори можуть допомогти вам перевірити нову функцію та оновити ваш код:

Дізнайтеся більше про вирази збору у цій статті на MS Learn.


Первинні конструктори для будь-якого класу або структури

 

У C# 12 розширено можливості первинних конструкторів для роботи з усіма класами та структурами, а не лише із записами. Первинні конструктори дозволяють вам визначати параметри конструктора під час оголошення класу:

Найпоширеніші способи використання первинного параметра конструктора


  • Як аргумент для виклику конструктора base().

  • Для ініціалізації поля або властивості члена.

  • Посилання на параметр конструктора у члені екземпляру.

  • Для усунення шаблонів при ін'єкції залежностей.


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


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


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


Дізнайтеся більше про первинні конструктори у цій статті. Щоб дізнатися більше про використання первинних конструкторів для записів і не-записів, перегляньте Підручник: Вивчення первинних конструкторів.


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

 

Псевдонімизація типів - це зручний спосіб прибрати складні сигнатури типів з вашого коду. Починаючи з C# 12, у директивах alias можна using додаткові типи. Наприклад, у більш ранніх версіях C# ці псевдоніми не працюють:



Ви можете ознайомитися зі специфікацією директиви Allow using alias, яка дозволяє посилатися на будь-який тип для using псевдонімів з вказівниками та небезпечними типами.


Як і інші псевдоніми, ці типи можна using у верхній частині файлу та у global using операторах.


Дізнайтеся більше про псевдонім будь-якого типу у цій статті.


Лямбда-параметри за замовчуванням

Починаючи з C# 12, у лямбда-виразах можна оголошувати параметри за замовчуванням:

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


Дізнайтеся більше про лямбда-параметри за замовчуванням у цій статті.


Прискорюємо ваш код

Ми продовжуємо вдосконалювати ваші можливості роботи з необробленою пам'яттю, щоб підвищити продуктивність додатків.


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


У C# 12 ми додали параметри ref readonly та вбудовані масиви.


параметри ref readonly

Додавання параметрів ref readonly забезпечує остаточну комбінацію передачі параметрів за посиланням або за значенням. Аргумент параметра ref readonly повинен бути змінною. Подібно до аргументів ref та out, аргумент не повинен бути буквальним значенням або константою. Буквальний аргумент генерує попередження і компілятор створює тимчасову змінну. Як і in параметрах, параметр ref readonly не може бути змінений. Метод повинен оголошувати параметри ref readonly, якщо він не буде змінювати аргумент, але потребує його ділянку пам'яті.


Дізнайтеся більше про параметри ref readonly у цій статті.


вбудовані масиви

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


Дізнайтеся більше про вбудовані масиви у цій статті.


Допомагають нам працювати швидше

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


Атрибут експериментальності

Іноді ми розміщуємо функції у випущених версіях .NET або C#, тому що ми хочемо отримати зворотній зв'язок або функція не може бути завершена за один цикл. У цих випадках ми хочемо дати зрозуміти, що ми ще не взяли на себе зобов'язань щодо цієї функції або її реалізації. Ми додали атрибут System.Diagnostics.CodeAnalysis.ExperimentalAttribute, щоб краще пояснити, коли це відбувається.


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


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


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


Дізнайтеся більше про атрибут експериментальний у цій статті.


Перехоплювачі

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


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


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


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

C# 12 - це лише частина захоплюючого випуску .NET 8. Ви можете дізнатися про інші можливості в блозі про .NET 8.


Завантажуйте .NET 8, Visual Studio 2022 17.8 і знайомтеся з C# 12!

 

Source






Posted on 8. November 2023

The convenience of System.IO

Зручність System.IO



Читання та запис файлів дуже поширені, як і інші форми введення-виведення. Файлові API потрібні для читання конфігурації програми, кешування вмісту та завантаження даних (з диска) у пам’ять для виконання деяких обчислень, наприклад (сьогоднішня тема) підрахунок слів. File, FileInfo, FileStreamFile, FileInfo, FileStream, і подібні типи виконують велику роботу для розробників .NET, яким потрібен доступ до файлів. У цій публікації ми розглянемо зручність і продуктивність читання текстових файлів з System.IO з допомогою API System.Text.


Нещодавно ми запустили серію про зручність .NET , яка описує наш підхід до надання зручних рішень для поширених завдань. Зручність System.Text.Json — ще одна публікація в серії про читання та написання документів JSON. Чому .NET? описує варіанти архітектури, які дозволяють використовувати рішення, розглянуті в цих публікаціях.


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

API

Наступні File API (з їхніми супутніми програмами) використовуються в тестах.

1. File.OpenHandle з RandomAccess.Read

2. File.Open з FileStream.Read

3. File.OpenText з StreamReader.ReadіStreamReader.ReadLine

4. File.ReadLines зIEnumerable<string>

5. File.ReadAllLines з string[]

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


Тести нижчого рівня спираються на такі типи System.Text:

Кодування

Руна

Я також використовував новий клас SearchValues, щоб перевірити, чи дає він значну перевагу перед передачеюSpan<char> в Span<char>.IndexOfAny. Він попередньо обчислює стратегію пошуку, щоб уникнути попередніх витрат IndexOfAny. Спойлер: ефект драматичний.


Далі ми розглянемо програму, яка була реалізована кілька разів — для кожного з цих API — тестування доступності та ефективності.

Застосунок

Програма підраховує рядки, слова та байти в текстовому файлі. Він змодельований на основі поведінки wc, популярного інструменту, доступного в Unix-подібних системах.


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


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


Це з wc --help. Код програми має відповідати цьому рецепту. Здається простим.


Тести підраховують слова в Кларисі Гарлов; або історія молодої леді Семюела Річардсона. Цей текст було вибрано тому, що це, очевидно, одна з найдовших книг англійською мовою та є у вільному доступі на Project Gutenberg . Є навіть його телевізійна адаптація BBC 1991 року.


Я також провів деякі тести з Знедоленими, ще одним довгим текстом. На жаль, 24601 не підійшов через кількість слів.

Результати

Кожна імплементація вимірюється з точки зору:

– Рядків коду

– Швидкості виконання

– Використання пам'яті

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


Я використовував BenchmarkDotNet для тестування продуктивності. Це чудовий інструмент, якщо ви ніколи ним не користувалися. Написання контрольного тесту подібне до написання модульного тесту.

 

Наступне використання wc містить список ядер на моїй машині Linux. Кожне ядро ​​отримує свій власний рядок у файлі /proc/cpuinfo з «назвою моделі», яка з’являється в кожному з цих рядків -l і підраховує рядки.

Я використовував цю машину для тестування продуктивності в публікації. Ви бачите, що я використовую Manjaro Linux, який є частиною сімейства Arch Linux. .NET 8 уже доступний у Arch User Repository (який також доступний для користувачів Manjaro).


Рядки коду

Я люблю прості та доступні рішення. Рядки коду є нашою найкращою проксі-метрикою для цього.

На цій діаграмі є два кластери на ~35 і ~75 лініях. Ви побачите, що ці тести зводяться до двох алгоритмів з деякими невеликими відмінностями для адаптації до різних API. Навпаки, wc реалізація трохи довша, близько 1000 рядків. Однак вона робить більше.


Раніше я використовував wc, щоб обчислювати кількість рядків Benchmark знову з -l.

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


Функціональне співвідношення з wc

 

Давайте переконаємось, що моя реалізація C# відповідає wc.

 

І з count, окремою копією FileOpenHandleCharSearchValuesBenchmark:

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


Перегляньте підсумок(за 10 мікросекунд)

 

Я почав з тестування короткого змісту роману. Це лише 1 кілобайт (9 рядків і 153 слова).

Давайте порахуємо кілька слів.

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


Команда byte виграє гонку пам’яті в команди string

Давайте подивимося на використання пам'яті для того самого найменшого документа.

Примітка: 1_048_576  байт — це 1 мегабайт (мебібайт) . 10_000 байтів становить 1% від цього. Примітка. Я використовую формат цілочисельного літералу.


Ви бачите один кластер API, який повертає байти, і інший, який повертає рядки, розподілені у купі. Посередині File.OpenText повертає значення типу char.


File.OpenText покладається на класи StreamReader і FileStream для виконання необхідної обробки. API, що повертають string, покладаються на ті самі типи. Об’єкт StreamReader, який використовується цими API, виділяє кілька буферів, включаючи буфер розміром 1 Кб. Він також створює об’єкт FileStream, який за замовчуванням виділяє буфер 4k. Для File.OpenText(при використанні StreamReader.Read) ці буфери мають постійну вартість, в той час як File.ReadLines та File.ReadAllLines також виділяють рядки (по одному на лінію; змінна вартість).

Швидкість читання книги (за 1 мілісекунду)

 

Давайте подивимося, скільки часу потрібно для підрахунку рядків, слів і байтів у першій частині Клариси Гарлов

Можливо, ми побачимо більший розподіл у продуктивності, продираючись через 610_515 байтів тексту.

API, що повертають byte і char, кластеризуються разом, трохи більше ніж за 1 мс. Ми також бачимо різницю між File.ReadLine і File.ReadAllLines. Однак, слід мати на увазі, що розрив складає лише 2 мс для 600k тексту. Високорівневі API чудово справляються із завданням забезпечення конкурентоспроможної продуктивності за допомогою набагато простіших алгоритмів (у написаному мною коді).


Різницю в File.ReadLine і File.ReadAllLines варто пояснити трохи докладніше.

– Усі API починаються з байтів. File.ReadLines читає значення bytes у char, шукає наступний розрив рядка , потім перетворює цей блок тексту на string, повертаючи по одному .

File.ReadAllLines робить те саме й додатково створює всі рядки string одночасно та пакує їх усі у string[]. Це БАГАТО попередньої роботи, яка потребує багато додаткової пам’яті, яка часто не дає додаткової цінності.


File.OpenText повертає StreamReader, який відкриває API ReadLine та Read. Перший повертає string, а другий одне або інше значення char. Цей параметр ReadLine дуже схожий на використання File.ReadLines, який побудовано на тому ж API. На діаграмі я показав File.OpenText використовуючи StreamReader.Read. Це набагато ефективніше.

Пам'ять: найкраще читати сторінку за раз

Виходячи з різниці у швидкості, ми, ймовірно, також побачимо значні відмінності в пам’яті.

Давайте будемо милосердними. Це драматична різниця. API низького рівня мають фіксовану вартість, тоді як вимоги до пам’яті API string масштабуються відповідно до розміру документа.

 

Написані мною тести FileOpenHandle і FileOpen використовують масиви ArrayPool, вартість якого не відображається в тесті.

Цей код показує два масиви ArrayPool, які використовуються (і їхні розміри). Виходячи зі спостережень, існує значна перевага для продуктивності з буфером 4k і обмеженим (або відсутнім). Буфер 4k здається розумним для обробки файлу 600k.


Я міг би використати приватні масиви (або прийняти буфер від абонента). Моє використання масивів ArrayPool демонструє різницю у використанні пам’яті в основних API. Як бачите, вартість File.Open та File.OpenHandle фактично дорівнює нулю (принаймні, відносно).


Тим не менш, використання пам'яті моїми бенчмарками FileOpen та FileOpenHandle буде дуже схожим на FileOpenText якби я не використовував ArrayPool. Це повинно дати вам уявлення про те, що FileOpenText працює досить добре (якщо не використовувати StreamReader.ReadLine). Звичайно, мою реалізацію можна було б оновити, щоб використовувати набагато менші буфери, але тоді вона працюватиме повільніше.

Паритет продуктивності з wc

Я продемонстрував, що System.IO можна використовувати для отримання тих самих результатів, що й wc. Мені так само слід порівняти продуктивність, використовуючи мій найкращий тест. Тут я використаю команду time для запису всього виклику (від початку до завершення процесу), обробляючи як один том (роману), так і всі томи. Ви побачите, що весь роман (усі 9 томів) складається з понад 5 МБ тексту та трохи менше ніж 1 млн слів.


Почнемо з wc.

Це досить швидко, 9 і 26 мілісекунд.

 

Давайте спробуємо з .NET, використовуючи мою реалізацію

FileOpenHandleCharSearchValuesBenchmark.

Погано! Навіть не близько.

Це 70 і 124 мілісекунди з .NET порівняно з 9 і 26 мілісекундами з wc. Насправді цікаво, що тривалість не залежить від розміру вмісту, особливо з реалізацією .NET. Вартість запуску під час роботи явно домінує.

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


О! У нас воно є. У нас є нативний АОТ. Давайте спробуємо.


Оскільки мені подобається використовувати контейнери, я використав один із наших образів контейнерів SDK (з монтуванням тому), щоб виконати компіляцію, щоб мені не довелося нативний інструментарій на своїй машині.

Якщо ви уважно придивитесь, то побачите, що програма для порівняння компілюється до < 2 МБ (1_944_896) із рідним AOT. Це середовище виконання, бібліотеки та код програми. Все. Насправді файл символів (count.dbg) більший. Я можу перенести цей виконуваний файл на комп’ютер Ubuntu 22.04 x64, наприклад, і просто запустити його.


Давайте перевіримо нативний AOT.

Маємо 4 і 22 мілісекунди з рідним AOT порівняно з 9 і 25 з  wc. Це чудові результати та досить конкурентоспроможні! Цифри настільки хороші, що мені майже довелося б ще раз перевірити, але підрахунки підтверджують обчислення.

Примітка. Я налаштував програму за допомогою <OptimizationPreference>Speed</OptimizationPreference>. Це дало невелику користь.

Текст, руни та Юнікод

Текст є всюди. Насправді ви його зараз читаєте. .NET містить декілька типів для обробки та зберігання тексту, зокрема Char, Encoding, Rune та String.


Юнікод кодує понад мільйон символів, у тому числі емодзі . Перші 128 символів ASCII і Unicode збігаються. Є три кодування Unicode : UTF8, UTF16 і UTF32, із різною кількістю байтів, які використовуються для кодування кожного символу.


Ось трохи (напіввідповідного) тексту з «Гобіта».


— Місячні літери — це рунічні літери, але їх не видно, — сказав Елронд

Я не можу не думати, що місячні літери є фантастичними пробілами .

 

Ось результати невеликої утиліти , яка друкує інформацію про кожен символ Unicode, використовуючи цей текст. Довжина байтів і байти є специфічними для представлення UTF8.

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


Двійкове представлення символів, які використовують однобайтове кодування, точно відповідає їхнім цілим значенням кодової точки. Наприклад, двійкове представлення кодової точки «M» (77) –  0b01001101 таке ж, як ціле число 77. Навпаки, двійкове представлення цілого числа 8220 є 0b_100000_00011100, а не трибайтове двійкове значення, яке ми бачимо вище для . Це тому, що кодування Unicode описує більше, ніж просто значення кодової точки .

 

Ось ще одна програма , яка має надати ще більше розуміння .

Він виводить наступне:

 

Я можу знову запустити програму, змінивши кодування на UTF16. Я змінив значення encoding на Encoding.Unicode.

Це вказує нам на кілька речей:

– Кодування UTF8 має нерівномірне кодування байтів.

– Кодування UTF16 більш однорідне.

– Символи, для яких потрібна одна кодова точка, можуть взаємодіяти з int, створюючи такі шаблони, як (char)8220 або(char)0x201C.

– Символи, які вимагають двох кодових точок, можна зберігати в string, цілочисельному значенні (UTF32) або як Rune, дозволяючи шаблони, такі як (Rune)128512.

– Легко писати програмне забезпечення з помилками, якщо код безпосередньо обробляє символи або (що ще гірше) байти. Наприклад, уявіть собі, що ви пишете алгоритм текстового пошуку, який підтримує терміни пошуку emoji .

– Багатокодових символів достатньо, щоб запустити будь-якого розробника.

– Мій термінал підтримує emoji (і я цьому дуже радий).


Ми можемо зв’язати ці концепції Unicode з типами .NET.

string та char використовують кодування UTF16.

– Класи Encoding дозволяють обробляти текст між кодуваннями та значеннями byte.

string підтримує символи Unicode, які потребують однієї або двох кодових точок.

Rune може представляти всі символи Unicode (включаючи сурогатні пари), на відміну від char.


Усі ці типи використовуються в тестах. Усі контрольні тести (крім одного, який обманює) належним чином використовують ці типи, щоб правильно обробляти текст Unicode.


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


File.ReadLines та File.ReadAllLines

Наступні контрольні тести реалізують високорівневий алгоритм на основі рядків string:

FileReadLines

FileReadAllLinesBenchmark

 

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


Показник FileReadLines встановлює основу для нашого аналізу. Він використовує foreach понад IEnumerable<string>.

}

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

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


Результати в основному відповідають інструменту wc. Кількість байтів не збігається, оскільки цей код працює з символами, а не з байтами. Це означає, що позначки порядку байтів , багатобайтові кодування та символи завершення рядка були приховані від очей. Я міг би додати +1 до charCount кожного рядка, але це не здалося мені корисним, особливо тому, що існує кілька схем нового рядка . Я вирішив точно підрахувати символи або байти і не намагатися приблизно оцінити різницю між ними.


Підсумок: ці API чудово підходять для невеликих документів або коли використання пам’яті не є сильним обмеженням. Я б використовував, лише File.ReadAllLines якщо б мій алгоритм покладався на знання кількості рядків у документі наперед і лише для невеликих документів. Для великих документів я б застосував кращий алгоритм для підрахунку символів розриву рядка, щоб уникнути використання цього API.

File.OpenText

У наведених нижче контрольних тестах реалізовано різноманітні підходи, усі вони базуються на StreamReader, в якому File.OpenText є просто оболонкою. Деякі з API StreamReader відображають рядки string, а інші – значення char. Саме тут ми побачимо більшу різницю в продуктивності.

FileOpenTextReadLineBenchmark

FileOpenTextReadLineSearchValuesBenchmark

FileOpenTextCharBenchmark

FileOpenTextCharLinesBenchmark

FileOpenTextCharIndexOfAnyBenchmark

FileOpenTextCharSearchValuesBenchmark


Метою цих бенчмарок є визначення переваг SearchValues і переваг char порівняно з string Я також включив показник FileReadLinesBenchmark як базовий із попереднього набору контрольних показників.

Ви можете запитати про пам’ять. Використання пам’яті StreamReader є функцією char vs string, яку ви можете побачити на початкових діаграмах пам’яті раніше в публікації. Відмінності в цих алгоритмах впливають на швидкість, але не на пам'ять.


Бенчмарк FileOpenTextReadLineBenchmark фактично ідентичний  FileReadLines, тільки без абстракції IEnumerable<string>


Бенчмарк FileOpenTextReadLineSearchValuesBenchmark починає ставати трохи привабливішим.

Цей тест просто підраховує пробіли (які він не обрізає). Він використовує переваги нового типу SearchValues, який може пришвидшити IndexOfAny при пошуку не лише кількох значень. Об’єкт SearchValues створено з пробілами, крім (більшості) символів розриву рядка. Ми можемо припустити, що символи розриву рядка більше не присутні, оскільки код покладається на StreamReader.ReadLine.


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


Значною частиною причини, чому IndexOfAny так добре працює, є векторизація.

.NET 8 містить векторні API аж до 512 біт. Ви можете використовувати їх у власних алгоритмах або покластися на вбудовані API, щоб IndexOfAny отримав перевагу від покращеної обчислювальної потужності. Зручне API IsHardwareAccelerated повідомляє вам, наскільки великі векторні регістри на даному ЦП. Це результат на моїй машині Intel. Я експериментував із новим апаратним забезпеченням Intel, доступним у Azure, яке повідомляло Vector512.IsHardwareAccelerated як True. Моя машина MacBook M1 повідомляє Vector128.IsHardwareAccelerated як найвищу доступну.


Тепер ми можемо залишити землю string і перейти до значення char. Є дві очікувані великі переваги. Перша полягає в тому, що базовому API не потрібно читати наперед, щоб знайти символ розриву рядка, і більше не буде рядків для розподілу купи та збору сміття. Ми повинні побачити помітне покращення швидкості, і ми вже знаємо з попередніх діаграм, що є значне зменшення пам’яті.


Я побудував наступні тести, щоб оцінити цінність різних стратегій.

FileOpenTextCharBenchmark — Той самий базовий алгоритм, що й FileReadLines із додаванням перевірки розривів рядків.

FileOpenTextCharLinesBenchmark — Спроба спростити основний алгоритм шляхом синтезу рядків символів.

FileOpenTextCharSearchValuesBenchmark — Подібне використання SearchValues як FileOpenTextReadLineSearchValuesBenchmark для прискорення пошуку простору, але без попередньо обчислених рядків.

FileOpenTextCharIndexOfAnyBenchmark — Точно такий самий алгоритм, але який використовує IndexOfAny з Span<char> замість нових типів SearchValues.


Ці бенчмарки (як показано на діаграмі вище) говорять нам про те, що використовувати IndexOfAny з SearchValues<char> дуже корисно. Цікаво подивитися, наскільки погано IndexOfAny працює, якщо дано стільки значень (25) для перевірки. Виходить набагато повільніше, ніж просто перемикання кожного символу з перевіркою char.IsWhiteSpace. Ці результати мають зупинити вас, якщо ви використовуєте великий набір пошукових термінів із IndexOfAny.


Я провів деякі тести на деяких інших машинах. Я помітив, що FileOpenTextCharLinesBenchmark працює досить добре на машині AVX512 (з нижчою тактовою частотою). Можливо, це пов’язано з тим, що він більшою мірою покладається на IndexOfAny (тільки з двома пошуковими термінами) і в іншому випадку є досить економним алгоритмом.


Ось імплементація FileOpenTextCharSearchValuesBenchmark.

Це не дуже відрізняється від оригінальної реалізації. Перший блок повинен враховувати розриви рядків у перевірці  char.IsWhiteSpace. Після цього IndexOfAny використовується з SearchValue<char> для пошуку наступного пробілу, щоб можна було виконати наступну перевірку. Якщо IndexOfAny повертає -1, ми знаємо, що пробілів більше немає, тому нема потреби читати далі буфер.


Span<T> повсюдно використовується  в цій реалізації. Проміжки забезпечують дешевий спосіб створення вікон у базовому масиві. Вони настільки дешеві, що реалізація може продовжувати нарізку аж до тих пір, поки chars.Length > 0 більше не буде правдивим. Я використовував цей підхід лише з алгоритмами, які вимагали фрагментів >1 символів одночасно. В іншому випадку я використовував цикл for для повторення Span, що було швидше.


Примітка: Visual Studio запропонує, що chars.Slice(1) можна спростити до chars[1..]. Я виявив, що спрощення не є еквівалентним і відображається як регресія продуктивності в контрольних тестах. Набагато менша ймовірність виникнення проблеми в програмах.

Бенчмарки FileOpenTextChar* набагато ближчі до відповідності з wc для байтових результатів (для тексту ASCII). Позначка порядку байтів (BOM) споживається, перш ніж ці API починають повертати значення. Як наслідок, кількість байтів для API, що повертають char, постійно змінюється на три байти (розмір специфікації). На відміну від API, що повертають string, тут враховуються всі символи розриву рядка.



Підсумок: StreamReader (який є основою File.OpenText) пропонує гнучкий набір API, що охоплює широкий діапазон доступності та продуктивності. Для більшості випадків використання (якщо File.ReadLines не підходить) StreamReader це чудовий вибір за замовчуванням.

File.Open та File.OpenHandle

У наведених нижче тестах реалізовано алгоритми найнижчого рівня на основі байтів. File.Open є оболонкою на FileStream. File.OpenHandle повертає дескриптор операційної системи, до якого потрібен RandomAccess.Read для доступу.

FileOpenCharSearchValuesBenchmark

FileOpenHandleCharSearchValuesBenchmark

FileOpenHandleRuneBenchmark

FileOpenHandleAsciiCheatBenchmark


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

Кількість байтів тепер збігається. Тепер ми переглядаємо кожен байт у даному файлі.

FileOpenHandleCharSearchValuesBenchmark додає кілька нових концепцій. FileOpenCharSearchValuesBenchmark фактично ідентичний.

Остання спроба порівняти результати wc.

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

Наступні два блоки коду є новими.

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

Цей блок декодує буфер байтів у символьний буфер. Обидва буфери мають правильний розмір (з AsSpan) відповідно до повідомлених підрахованих значень byte та char. Після цього код приймає більш звичний алгоритм char. Немає очевидного способу використання SearchValues<byte>, який добре поєднується з багатобайтовим кодуванням Unicode. Цей підхід добре працює, тому це не має великого значення.


Ця публікація про зручність. Я виявив, що Decoder.GetChars це неймовірно зручно. Це чудовий приклад низькорівневого API, який робить саме те, що потрібно, і начебто рятує день у окопах. Я знайшов цю закономірність, прочитавши, як File.ReadLines (опосередковано) вирішує саме цю проблему. Весь цей код можна переглянути. Це відкритий код!


FileOpenHandleRuneBenchmark використовує клас Rune замість Encoding. Це виглядає повільніше, частково тому, що я повернувся до більш базового алгоритму. Не було очевидно, як використовувати IndexOfAny або SearchValues з Rune, частково тому, що не існує аналога decoder.GetChars для Rune.

Тут немає особливої ​​різниці, і це добре. Rune значною мірою замінює char.

 

Цей рядок є ключовою відмінністю.

Мені потрібен API, який повертає символ Unicode зSpan<byte> та повідомляє про кількість прочитаних байтів. Це може бути від 1 до 4 байтів. Rune.DecodeFromUtf8 робить саме це. Для моїх цілей мені байдуже, чи отримаю я назад Rune чи char. Вони обидві є структурами.


Я залишив FileOpenHandleAsciiCheatBenchmark наостанок. Я хотів побачити, наскільки швидше можна було б змусити код працювати, якщо він міг застосувати максимальну кількість припущень. Коротше кажучи, як би виглядав алгоритм лише ASCII?

 

Цей код майже ідентичний тому, що ви бачили раніше, за винятком того, що він шукає набагато менше символів, що — СЮРПРИЗ — прискорює роботу алгоритму. Ви можете побачити це на діаграмі раніше в цьому розділі. SearchValues тут не використовується, оскільки він не оптимізований лише для двох значень.

Цей алгоритм все ще здатний давати очікувані рез

ультати. Це лише тому, що текстовий файл задовольняє припущення коду.

Підсумок: File.Openі File.OpenHandleпропонують найвищий контроль і продуктивність. У випадку текстових даних неочевидно, що варто докладати додаткових зусиль над File.OpenTextchar), навіть якщо вони можуть забезпечити вищу продуктивність. У цьому випадку ці API повинні відповідати базовій лінії підрахунку байтів. Для нетекстових даних ці API є більш очевидним вибором.

Резюме

System.IO надає ефективні API, які охоплюють багато випадків використання. Мені подобається, як легко створювати прості алгоритми за допомогою File.ReadLines. Це працює дуже добре для вмісту, який базується на рядках. File.OpenText дозволяє писати швидші алгоритми без значного ускладнення. Нарешті,  File.Open  таFile.OpenHandle чудово підходять для отримання доступу до двійкового вмісту файлів і для написання найбільш високопродуктивних і точних алгоритмів.


Я не збирався досліджувати API глобалізації .NET або Unicode настільки глибоко. Раніше я використовував API кодування, але ніколи не пробував Rune. Я був вражений тим, наскільки добре ці API підходять для мого проєкту та наскільки добре вони можуть працювати. Ці API були несподіваним прикладом зручності публікації. Зручність означає не «високий рівень», а «правильний і доступний інструмент для роботи».


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

 

Source








Posted on 5. November 2023

What’s new with identity in .NET 8

Що нового в ідентифікації в .NET 8


У квітні 2023 року я писав про зобов’язання команди ASP.NET Core покращити автентифікацію, авторизацію та керування ідентифікацією в .NET 8. Представлений нами план включав три основні результати:


– Нові API для спрощення входу та керування ідентифікацією для клієнтських програм, таких як Single Page Apps (SPA) і Blazor WebAssembly.

– Увімкнення автентифікації та авторизації на основі маркерів у ASP.NET Core Identity для клієнтів, які не можуть використовувати файли cookie.

– Покращення в документації.


Усі три результати з’являтья разом із .NET 8. Крім того, ми змогли додати новий інтерфейс ідентифікації для веб-програм Blazor, який працює з обома новими режимами візуалізації, сервером і WebAssembly.


Давайте розглянемо кілька сценаріїв, уможливлених новими змінами в .NET 8. У цій публікації блогу ми розглянемо:

– Захист простого серверного веб-API

– Використання нового інтерфейсу ідентифікатора Blazor

– Додавання зовнішнього логіна, наприклад Google або Facebook

– Захист програм Blazor WebAssembly за допомогою вбудованих функцій і компонентів

– Використання токенів для клієнтів, які не можуть використовувати файли cookie


Давайте розглянемо найпростіший сценарій використання нових функцій ідентифікації.

Базовий сервер веб-API

Простий спосіб використання нової авторизації — увімкнути її в базовій програмі Web API. Цю ж програму також можна використовувати як серверну частину для Blazor WebAssembly, Angular, React та інших односторінкових веб-програм (SPA). Якщо ви починаєте з проекту ASP.NET Core Web API у .NET 8, який включає OpenAPI, ви можете додати автентифікацію за кілька кроків.


Ідентифікація є "опціональною", тож залишилося додати ще кілька пакунків:

Microsoft.AspNetCore.Identity.EntityFrameworkCoreпакет, який забезпечує інтеграцію EF Core

– Пакет для бази даних, яку ви бажаєте використати, наприклад Microsoft.EntityFrameworkCore.SqlServer(у цьому прикладі ми використаємо базу даних у пам’яті)

 

Ви можете додати ці пакети за допомогою менеджера пакетів NuGet або командного рядка. Наприклад, щоб додати пакети за допомогою командного рядка, перейдіть до теки проєкту та виконайте такі команди dotnet:

 

Ідентифікація дозволяє налаштувати як інформацію про користувача, так і базу даних користувача, якщо у вас є вимоги, що виходять за межі того, що надається в рамках .NET Core. Для нашого базового прикладу ми просто використаємо інформацію про користувача та базу даних за замовчуванням. Для цього ми додамо новий клас до проєкту під назвою, MyUser, який успадковує від IdentityUser:

 

Додайте новий клас під назвою AppDbContext, який успадковує від IdentityDbContext<MyUser>:

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


Щоб налаштувати ідентифікатор для програми, відкрийте файл Program.cs. Налаштуйте ідентифікатор на використання автентифікації на основі файлів cookie та ввімкніть перевірку авторизації, додавши наступний код після виклику WebApplication.CreateBuilder(args):

 

Налаштуйте базу даних EF Core. Тут ми використаємо базу даних у пам’яті та назвемо її «AppDb». Вона використовується тут для демонстрації, тому можна легко перезапустити програму та перевірити потік, щоб зареєструватися та ввійти (кожний запуск розпочинатиметься з новою базою даних). Перехід на SQLite збереже користувачів між сеансами, але вимагає належного створення бази даних за допомогою міграцій, як показано в цьому посібнику з початку роботи з EF Core. Ви можете використовувати інші реляційні постачальники, такі як SQL Server, для свого робочого коду.

 

Налаштуйте ідентифікацію для використання бази даних EF Core та відкрийте кінцеві точки ідентифікації:

 

Позначте маршрути для кінцевих точок ідентифікації. Цей код слід розмістити після виклику builder.Build():

Тепер програма готова до автентифікації та авторизації! Щоб захистити ендпоінт, використовуйте метод розширення .RequireAuthorization(), де ви визначаєте маршрут авторизації. Якщо ви використовуєте рішення на основі контролера, ви можете додати атрибут [Authorize]до контролера або дії.

Щоб протестувати програму, запустіть її та перейдіть до інтерфейсу користувача Swagger. Розгорніть захищений ендпоінт, оберіть «випробувати» та виберіть «Виконати». Ендпоінт отримує повідомлення 404 - not found, що, мабуть, є більш безпечним, ніж повідомлення, 401 - not authorized оскільки воно не показує, що кінцева точка існує.

Swagger UI з 404

Тепер розгорніть /register і заповніть свої облікові дані. Якщо ви введете недійсну адресу електронної пошти або неправильний пароль, результат міститиме помилки перевірки.

Swagger UI з помилками перевірки

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


Успішна реєстрація призводить до відповіді 200 - OK. Тепер ви можете розгорнути /login та ввести ті самі облікові дані. Зауважте, що для цього прикладу є додаткові параметри, які можна видалити. Обов’язково встановіть useCookies true. Успішний вхід призводить до відповіді 200 - OK з файлом cookie в заголовку відповіді.

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


Деякі веб-клієнти можуть не включати файли cookie в заголовок за умовчанням. Якщо ви використовуєте інструмент для тестування API, вам може знадобитися ввімкнути файли cookie в налаштуваннях. JavaScript API fetch не включає файли cookie за замовчуванням. Ви можете ввімкнути їх, встановивши значення credentials як  include в параметрах. Подібним чином, HttpClient запущений в програмі Blazor WebAssembly потребує HttpRequestMessage для включення облікових даних, наприклад:

Далі перейдемо до веб-програми Blazor.


Інтерфейс ідентифікації Blazor


Велика мета нашої команди, якої ми змогли досягти, полягала в тому, щоб реалізувати користувальницький інтерфейс ідентифікації, який включає параметри реєстрації, входу та налаштування багатофакторної автентифікації в Blazor. Інтерфейс користувача вбудовано в шаблон, коли ви вибираєте параметр «Індивідуальні облікові записи» для автентифікації. На відміну від попередньої версії інтерфейсу ідентифікації, яка була прихована, якщо ви не хотіли її налаштувати, шаблон генерує весь вихідний код, щоб ви могли змінювати його за потреби. Нова версія створена на основі компонентів Razor і працює як із серверними програмами, так і з програмами WebAssembly Blazor.

Сторінка входу Blazor

Нова веб-модель Blazor дозволяє вам налаштувати, чи інтерфейс користувача відображатиметься на стороні сервера чи клієнта, що працює в WebAssembly. Якщо ви обираєте режим WebAssembly, сервер усе одно оброблятиме всі запити на автентифікацію та авторизацію. Він також створить код для спеціальної реалізації AuthenticationStateProvider, яка відстежує стан автентифікації. Постачальник використовує  клас PersistentComponentState для попереднього відтворення стану автентифікації та збереження його на сторінці. PersistentAuthenticationStateProvider у клієнтській програмі WebAssembly використовує компонент для синхронізації стану автентифікації між сервером і браузером. Постачальник стану також може бути названий PersistingRevalidatingAuthenticationStateProvider під час роботи з автоматичною інтерактивністю або IdentityRevalidatingAuthenticationStateProvider для інтерактивності сервера.

Незважаючи на те, що приклади в цій публікації блогу зосереджені на простому сценарії входу з іменем користувача та паролем, ASP.NET Identity підтримує взаємодію на основі електронної пошти, як-от підтвердження облікового запису та відновлення пароля. Також можна налаштувати багатофакторну автентифікацію. Компоненти для всіх цих функцій включені в інтерфейс користувача.

Додайте зовнішній логін

Нам часто задають питання, як інтегрувати зовнішні входи через соціальні веб-сайти з ASP.NET Core Identity. Починаючи з проєкту веб-програми Blazor за замовчуванням, ви можете додати зовнішній логін за кілька кроків.


По-перше, вам потрібно буде зареєструвати свою програму на веб-сайті соціальної мережі. Наприклад, щоб додати логін Twitter, перейдіть на портал розробників Twitter і створіть нову програму. Вам потрібно буде надати певну базову інформацію, щоб отримати облікові дані клієнта. Після створення програми перейдіть до налаштувань програми та натисніть «редагувати» під час автентифікації. Укажіть «нативний додаток» для типу додатка, щоб потік працював правильно, і ввімкніть «запитувати електронні листи від користувачів». Вам потрібно буде надати URL-адресу зворотного виклику. У цьому прикладі ми використаємо URL-адресу зворотного виклику https://localhost:5001/signin-twitter за умовчанням для шаблону веб-програми Blazor. Ви можете просто замінити цю адресу, щоб відповідати URL-адресі вашої програми (тобто замінити 5001 своїм власним портом). Також зверніть увагу на ключ і секрет API.

Далі додайте до своєї програми відповідний пакет автентифікації. Існує список постачальників соціальної автентифікації OAuth 2.0 для ASP.NET Core, який підтримується спільнотою, із багатьма варіантами на вибір. Ви можете комбінувати кілька зовнішніх входів за потреби. Для Twitter я додам пакет AspNet.Security.OAuth.Twitter.

 

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

 

Нарешті, налаштуйте вхід в Program.cs, замінивши цей код:

з цим кодом:

Файли cookie є кращим і найбезпечнішим підходом для впровадження ASP.NET Core Identity. Токени підтримуються за потреби та потребують налаштування IdentityConstants.BearerScheme. Токени є пропрієтарними, а потік на основі токенів призначений для простих сценаріїв, тому він не реалізує стандарти OAuth 2.0 або OIDC.

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

Сторінка входу Blazor у Twitter

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

Захист програм Blazor WebAssembly

Основною мотивацією для додавання нових ідентифікаційних API було  бажання полегшити розробникам захист їхніх браузерних програм, включаючи Single Page Apps (SPA) і Blazor WebAssembly. Немає значення, чи використовуєте ви вбудований постачальник ідентифікації, спеціальну систему входу чи хмарну службу, як-от Microsoft Entra, кінцевим результатом буде ідентифікація, яка або автентифікована за допомогою претензій і ролей, або не автентифікована. У Blazor ви можете захистити компонент Razor, додавши атрибут [Authorize] до компонента або до сторінки, на якій розміщено компонент. Ви також можете захистити маршрут, додавши .RequireAuthorization()метод розширення до визначення маршруту.

Повний вихідний код для цього прикладу доступний у сховищі зразків Blazor.

Тег AuthorizeView забезпечує простий спосіб обробки вмісту, до якого користувач має доступ. Доступ до стану автентифікації можна отримати через властивість context. Зверніть увагу на наступне:

Привітання буде показано всім. У випадку Blazor WebAssembly, коли клієнту може знадобитися асинхронна автентифікація через виклики API, вміст Authorizing буде показано під час запиту та вирішення стану автентифікації. Потім, залежно від того, пройшли ви автентифікацію чи ні, ви побачите своє ім’я або повідомлення про те, що ви не автентифіковані. Як саме клієнт дізнається, чи ви автентифіковані? Ось де з’являється AuthenticationStateProvider.

Сторінка App.razor загорнута в провайдера CascadingAuthenticationState. Цей провайдер відповідає за відстеження стану автентифікації та надання до нього доступу для решти програми. AuthenticationStateProvider впроваджується в провайдера та використовується для відстеження стану. AuthenticationStateProvider також вводиться в компонент AuthorizeView. Коли стан автентифікації змінюється, постачальник сповіщає компонент AuthorizeView, і вміст оновлюється відповідно.

 

По-перше, ми хочемо переконатися, що виклики API відповідно зберігають облікові дані. Для цього я створив обробник під назвою CookieHandler.

 

В Program.cs додав обробник до HttpClient і використав фабрику клієнтів, щоб налаштувати спеціальний клієнт для автентифікації.

 

AuthUrl - це URL-адреса сервера ASP.NET Core, на якому доступні API ідентифікації. Далі я створив CookieAuthenticationStateProvider, який успадковує AuthenticationStateProvider і перевизначає метод GetAuthenticationStateAsync. Основна логіка виглядає так:

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


Як програма дізнається, коли стан змінився? Ось як виглядає вхід із Blazor WebAssembly за допомогою ідентифікаційного API:

Після успішного входу викликається метод NotifyAuthenticationStateChanged базового класу AuthenticationStateProvider, щоб повідомити провайдера про зміну стану. Йому передається результат запиту нового стану автентифікації, щоб він міг перевірити наявність файлу cookie. Після цього провайдер оновить компонент AuthorizeView, і користувач побачить автентифікований вміст.

Токени

У рідкісних випадках, коли ваш клієнт не підтримує файли cookie, API входу надає параметр для запиту токенів. Видається спеціальний токен (який є власністю платформи ідентифікації ASP.NET Core), який можна використовувати для автентифікації наступних запитів. Токен передається в хедері  Authorization як маркер токена. Також надається токен оновлення. Це дозволяє вашій програмі запитувати новий токен, коли закінчується термін дії старого, не змушуючи користувача знову входити в систему. Токени не є стандартними веб-токенами JSON (JWT). Це рішення було прийнято навмисно, оскільки вбудована ідентифікація призначена в основному для простих сценаріїв. Параметр маркера не призначений для повнофункціонального постачальника послуг ідентифікації або сервера маркерів, а замість цього є альтернативою параметру cookie для клієнтів, які не можуть використовувати файли cookie.

Не впевнені, чи потрібен вам сервер токенів чи ні? Прочитайте документ, який допоможе вам вибрати правильне рішення ідентифікації ASP.NET Core. Шукаєте більш просунуте рішення ідентифікації? Прочитайте наш список рішень для керування ідентифікацією для ASP.NET Core.

Документи та зразки

Третій результат – документація та зразки. Ми вже представили нову документацію та будемо додавати нові статті та зразки, коли наблизимось до релізу .NET 8. Слідкуйте за релізом № 29452 – документація та зразки для ідентифікації в .NET 8, щоб відстежувати прогрес. Будь ласка, використовуйте випуск, щоб надіслати додаткову документацію або зразки, які ви шукаєте. Ви також можете посилатися на конкретні проблеми для різних документів і залишати там свої відгуки.

Висновок

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


Дізнайтеся більше про нові функції ідентифікації в документації ASP.NET Core .


Source




Posted on 20. July 2023

New C# 12 preview features

Нові можливості C# 12 preview

Visual Studio 17.7 Preview 3 та .NET 8 Preview 6 продовжують розвиток C# 12. Ця попередня версія включає функції, призначені для створення фундаменту для покращення продуктивності в майбутньому. Простий доступ до вбудованих масивів дозволить бібліотекам використовувати їх у більшій кількості програм без зайвих зусиль з вашого боку. У цій попередній версії дебютує експериментальна функція перехоплення, яка дозволяє генераторам перенаправляти код, наприклад, для забезпечення контекстно-залежної оптимізації.Нарешті, розширено можливості роботи функції nameof.

Ви можете отримати C# 12, встановивши останню попередню версію Visual Studio або останню версію .NET SDK. Щоб ознайомитися з можливостями C# 12, вам потрібно встановити мовну версію вашого проєкту на preview:

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

nameof - доступ до елементів екземпляра

 

Відтепер ключове слово nameof працює з іменами елементів, включно з початковими значеннями, статичними елементами та атрибутами:

Ви можете дізнатися більше в статті Що нового в C# 12.

Вбудовані масиви

Атрибут InlineArrayAttribute був представлений у середовищі виконання у попередньому випуску .NET 8. Це розширена функція, яка буде використовуватися переважно компілятором, бібліотеками .NET та деякими іншими бібліотеками. Атрибут ідентифікує тип, який можна розглядати як безперервну послідовність примітивів для ефективних, безпечних за типом, захищених від перевиконання індексованих/зрізаних вбудованих даних. Бібліотеки .NET підвищують продуктивність ваших програм та інструментів, що використовують вбудовані масиви.

Компілятор створює різні IL для доступу до вбудованих масивів. Це призводить до деяких обмежень, наприклад, не підтримуються шаблони списків. У більшості випадків доступ до вбудованих масивів здійснюється так само, як і до інших масивів. Різні IL дають приріст продуктивності без зміни коду:

Більшість людей використовують вбудовані масиви, а не створюють їх. Але корисно розуміти, як це працює. Інтегровані масиви швидкі, тому що вони покладаються на точний план заданої довжини. Вбудований масив - це тип з одним полем, позначений атрибутом InlineArrayAttribute, який вказує довжину масиву. У типі, що використовувався у попередньому прикладі, завдяки параметру атрибута програма створює сховище рівно для десяти елементів у Buffer10<T>:

Більше інформації в статті Що нового в C# 12.

Перехоплювачі

У цій версії представлено експериментальну можливість, яка називається interceptors (перехоплювачі). Вона призначена для розширених сценаріїв, зокрема для покращення випереджувальної компіляції (AOT). Як експериментальна частина .NET 8, вона може бути змінена або вилучена у майбутній версії. Таким чином, його не слід використовувати у продакшені.

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

Оскільки перехоплювачі є експериментальною можливістю, вам потрібно буде явно увімкнути їх у файлі проєкту:

Перехоплювачі дозволяють створювати цікаві шаблони коду. Ось кілька прикладів:

Виклики, відомі під час компіляції, такі як Regex.IsMatch(@"a+b+") з постійним шаблоном, можуть бути перехоплені, щоб використовувати статично згенерований код для оптимізації, сприятливої до AOT.

ASP.NET Мінімальні виклики API, такі як app.MapGet("/products", handler: (int? page, int? pageLength, MyDb db) => { ... }) можна перехопити, щоб зареєструвати статично згенеровану thunk, яка викликає користувацький обробник напряму, минаючи виділення та індексацію.

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

Статична роздільна здатність графів залежностей для впровадження залежностей, де provider.Register<MyService>() може бути перехоплений.

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

Serializers (серіалізатори) можуть генерувати специфічну для типу (де)серіалізацію на основі конкретного типу викликів, таких як Serialize<MyType>(), і все це під час компіляції.

Більшість програмістів не будуть використовувати перехоплювачі безпосередньо, але в будь-якому випадку вони відіграватимуть важливу роль у прагненні зробити ваші програми швидшими та простішими у розгортанні. Очікується, що перехоплювачі залишаться експериментальними у версії C# 12/.NET 8 і можуть бути включені в наступну версію C#.

Підсумок

Ви можете знайти більше інформації про всі функції, представлені на цей час, на сторінці Що нового в C# 12 в Microsoft Learn, а також відстежувати розвиток функцій C# 12 на сторінці Roslyn Feature Status.

Ви можете перевірити найновіші можливості C# 12, завантаживши останню попередню версію Visual Studio або останню версію .NET SDK і встановивши LangVersion для preview у файлі вашого проєкту.



Posted on 15. July 2023

Анонс .NET 8 Preview 6

 

 

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

 

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


Ви можете завантажити .NET 8 Preview 6 для Linux, macOS і Windows.


Будьте в курсі новинок у .NET 8 . Він оновлюватиметься протягом випуску.


А тепер поглянемо на нові функції .NET 8.

 

Покращення System.Text.Json

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

- Додано підтримку кешування для інкрементного генератора, що покращує продуктивність IDE у великих проєктах. https://github.com/dotnet/runtime/pull/86121 

- Покращене форматування згенерованого вихідного коду, включно з виправленням ряду проблем із відступами https://github.com/dotnet/runtime/pull/86526 , https://github.com/dotnet/runtime/pull/87557 

- Додано ряд нових діагностичних попереджень https://github.com/dotnet/runtime/pull/87980

- Виправлено ряд помилок, пов’язаних із роздільною здатністю модифікатора доступності https://github.com/dotnet/runtime/pull/87136 

- Гарантія, що типи ігнорованих або недоступних властивостей не включені генератором https://github.com/dotnet/runtime/pull/87383 

- Виправлено проблеми, пов’язані з підтримкою JsonNumberHandling https://github.com/dotnet/runtime/pull/87484 

- Виправлено підтримку рекурсивних типів колекцій https://github.com/dotnet/runtime/pull/87632 

- Виправлено підтримку спеціального конвертера для структур, що допускають значення NULL https://github.com/dotnet/runtime/pull/84208 

- Виправлено ряд помилок у реалізації синтаксичного аналізу атрибутів під час компіляції https://github.com/dotnet/runtime/pull/87796 

 

- Додано підтримку вкладеності декларацій JsonSerializerContext в довільних типах https://github.com/dotnet/runtime/pull/87829

 

JsonStringEnumConverter<TEnum>

Цей новий конвертер доповнює наявний клас JsonStringEnumConverter, який не підтримується в Native AOT.

Користувачі, які бажають націлитися на користувачів Native AOT, повинні анотувати свої типи переліків наступним шаблоном.

 

 

JsonConverter.Type

 

 

Нова властивість дозволяє користувачам шукати тип незагального образу JsonConverter:

 

Властивість має значення NULL, оскільки повертає null для екземплярів JsonConverterFactory і для typeof(T)екземплярів JsonConverter<T>.

 

Перевантаження методів ZipFile CreateFromDirectory та ExtractToDirectory на основі потоку

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

Симетрично ми додали перевантаження ZipFile.ExtractToDirectory, які дозволяють користувачам надавати потік, що містить архівований файл, і витягувати його вміст у файлову систему.

Ці API дозволяють уникнути необхідності використовувати диск як проміжний крок. Це може бути корисним у ситуаціях, коли дисковий простір обмежений, як, наприклад, у хмарних середовищах:

- CreateFromDirectory дозволяє не записувати заархівований результат на диск.

 

- ExtractToDirectory не вимагає, щоб заархівований файл знаходився на диску.

 Використання ZipFile.CreateFromDirectory

 

Використання ZipFile.ExtractToDirectory


Метрики API MetricCollector

MetricCollector — це новий клас, призначений для тестування сценаріїв. Раніше він називався InstrumentRecorder. Ми значно вдосконалили цей клас і перемістили його в пакет Microsoft.Extensions.Telemetry.Testing .

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

 

Наступний приклад демонструє, як використовувати цю функцію.

Використання MetricCollector

Представляємо генератор джерела перевірки параметрів

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


Використання перевірки параметрів


Якщо програма використовує ін’єкцію залежностей, вона може ін’єктувати перевірку за таким шаблоном.

 

Розширення перевантажень конструктора LoggerMessageAttribute для підвищення функціональності


Були введені нові LoggerMessageAttribute перевантаження конструктора, які пропонують більшу гнучкість у визначенні необхідних параметрів за допомогою скорочення коду. Нові перевантаження конструктора включають такі параметри, як визначення лише LogLevel і повідомлення, лише LogLevel або лише повідомлення.


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

 

Використання LoggerMessage

 

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

 

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

 

Покращення генератора джерела прив’язки конфігурації

У Прев’ю № 3 ми представили новий джерельний генератор для забезпечення AOT і зручної конфігурації в ASP.NET Core . Генератор є альтернативою існуючій реалізації на основі відображення. Відтоді ми внесли кілька покращень на основі відгуків спільноти, і генератор готовий, щоб люди могли спробувати його ще раз за допомогою Preview 6.


Приклад програми , яка використовує зв’язування конфігурації та публікується з AOT, змінюється від двох (2) попереджень аналізу AOT під час компіляції до жодного. ДДодаток не працював при виконанні, але тепер він працює.


Для використання генератора не потрібно змінювати вихідний код. Його ввімкнено за замовчуванням у веб-програмах Native AOT. Для інших типів проектів його вимкнено за замовчуванням, але ви можете керувати ним, додавши наступну властивість до свого проекту.

Ви можете знайти відомі проблеми тут .

 

Генерований джерелом COM Interop


Тепер у нас є новий джерельний генератор, який підтримує взаємодію з COM-інтерфейсами за допомогою підтримки взаємодії, створеної джерелом , з якої ми почали LibraryImportAttribute. Ви можете використовувати System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute, щоб позначити інтерфейс як інтерфейс COM для вихідного генератора. Потім генератор вихідного коду згенерує код, щоб увімкнути виклик із коду C# до некерованого коду, а також код, щоб увімкнути виклик із некерованого коду в C#. Цей джерельний генератор інтегрується з LibraryImportAttribute, і ви можете використовувати типи з параметрами GeneratedComInterfaceAttribute  і повертати типи в методах LibraryImportAttributе.

 

 

Генератор вихідних кодів COM забезпечує зрозумілий досвід роботи з IDE через аналізатори та виправлення коду. Це схоже на LibraryImportAttribute. Біля кожного інтерфейсу, який має System.Runtime.InteropServices.ComImportAttribute, лампочка пропонуватиме опцію перетворення на взаємодію, згенеровану джерелом. Це виправлення змінить інтерфейс для використання GeneratedComInterfaceAttribute. Біля кожного класу, який реалізує інтерфейс із GeneratedComInterfaceAttribute, лампочка запропонує опцію додати GeneratedComClassAttribute до типу. Після перетворення типів ви можете використовувати  свої методи DllImport, щоб використати LibraryImportAttribute з наявним там засобом виправлення коду. За допомогою цих двох лампочок можна легко перетворити наявний код взаємодії COM для використання нового взаємодії, створеного джерелом. Також є більше аналізаторів, які допомагають виявити місця, де ви можете змішувати COM-взаємодію, згенеровану джерелом, і на основі середовища виконання, що може потребувати додаткової роботи.

 

 

У рамках цього проекту ми оновили бібліотеку System.Transactions для використання нової взаємодії, створеної джерелом! Ми використали цей досвід, щоб допомогти вдосконалити аналізатори та засоби виправлення коду, щоб забезпечити якісний досвід міграції.

 

Використання GeneratedComInterface

 

GeneratedComClassAttribute

 

Генератор вихідного коду також підтримує новий System.Runtime.InteropServices.Marshalling.GeneratedComClassAttribute , щоб дозволити вам передавати ваші типи, які реалізують інтерфейси з System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute - атрибутованих інтерфейсів до некерованого коду. Генератор вихідного коду згенерує код, необхідний для надання COM-об’єкта, який реалізує інтерфейси та перенаправляє виклики до керованої реалізації.

 

Використання GeneratedComClassAttribute

 

Взаємодія з LibraryImportAttribute


Методи в інтерфейсах з підтримкою GeneratedComInterfaceAttribute всіх тих самих типів, що й LibraryImportAttribute, і LibraryImportAttribute отримують підтримку для атрибутованих типів GeneratedComInterface та  атрибутованих типів GeneratedComClass в цьому випуску.

Якщо у вашому коді C# використовуватиметься лише GeneratedComInterfaceAttribute - атрибутований інтерфейс або для обгортання COM-об’єкта з некерованого коду, або для обгортання керованого об’єкта з C# для некерованого коду, ви можете використовувати параметри у властивості GeneratedComInterfaceAttribute.Options, щоб налаштувати, який код буде згенеровано. Цей параметр дозволить вам не писати маршаллери для сценаріїв, які, як ви знаєте, не використовуватимуться.

 

Генератор джерела використовує новий тип System.Runtime.InteropServices.Marshalling.StrategyBasedComWrappers для створення та керування оболонками об’єктів COM і оболонками керованих об’єктів. Цей новий тип забезпечує очікувану взаємодію .NET з COM-взаємодією, а також надає точки налаштування для досвідчених користувачів. Якщо ваша програма має власний механізм для визначення типів із COM або якщо вам потрібно підтримувати сценарії, які наразі не підтримує COM, створений джерелом, ви можете розглянути можливість використання нового типу StrategyBasedComWrappers, щоб додати відсутні функції для вашого сценарію та отримати той самий .NET досвід користувача для ваших типів COM.

Обмеження

На цю мить вихідний генератор COM має такі обмеження. Ми не плануємо усувати ці обмеження в .NET 8, але можливо в майбутній версії .NET.

Немає підтримки інтерфейсів на основі IDispatch.

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

– Немає підтримки інтерфейсів на основі IInspectable.

Використовуйте інструмент CsWinRT , щоб створити код взаємодії для цих інтерфейсів.

– Немає підтримки спорідненості апартаментів.

Передбачається, що всі COM-об’єкти є безпотоковими. Підтримку спорідненості апартаментів можна впровадити вручну за допомогою реалізацій типу StrategyBasedComWrappers та спеціальної стратегії.

– Немає підтримки властивостей COM.

Вони можуть бути реалізовані вручну як методи в інтерфейсі.

– Немає підтримки подій COM.

Вони можуть бути реалізовані вручну за допомогою базових API COM.

– Не підтримується використання ключового слова new для активації COM CoClass.

 

Використовуйте LibraryImportAttribute для P/Invoke до CoCreateInstance API, щоб активувати CoClass.

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

https://github.com/dotnet/runtime/issues/31113

Хоча HttpClient деякий час підтримував різні типи проксі, усі вони дозволяють людині посередині бачити, до якого сайту підключається клієнт. (навіть для HTTPS URI) Проксі-сервер HTTPS дозволяє створити зашифрований канал між клієнтом і проксі-сервером, щоб усі наступні запити могли оброблятися з повною конфіденційністю.

Використання проксі HTTPS

– Unix: export all_proxy=https://x.x.x.x:3218

– Windows: set all_proxy=https://x.x.x.x:3218

 

Цим також можна керувати програмно через WebProxy .

 

System.Security: підтримка SHA-3

Підтримка примітивів хешування SHA-3 тепер доступна на платформах, які пропонують SHA-3. Зараз це Linux із OpenSSL 1.1.1+ і Windows 11 build 25324+.

API, де доступний SHA-2, тепер пропонують доповнення SHA-3. Воно містить SHA3_256, SHA3_384 і SHA3_512 для хешування; HMACSHA3_256, HMACSHA3_384, і HMACSHA3_512 для HMAC; HashAlgorithmName.SHA3_256, HashAlgorithmName.SHA3_384, та HashAlgorithmName.SHA3_512 для хешування, де алгоритм можна налаштувати; і RSAEncryptionPadding.OaepSHA3_256, RSAEncryptionPadding.OaepSHA3_384, та RSAEncryptionPadding.OaepSHA3_512 для шифрування RSA OAEP.

Використання API SHA-3 подібне до SHA-2, з додаванням властивості IsSupported, щоб визначити, чи пропонує платформа SHA-3.

Крім того, SHA-3 включає дві функції розширюваного виведення (XOF), SHAKE128 і SHAKE256. Вони доступні як Shake128і Shake256.

 

Підтримка SHA-3 наразі спрямована на підтримку криптографічних примітивів. Очікується, що конструкції та протоколи вищого рівня спочатку не повністю підтримуватимуть SHA-3. Це включає, але не обмежується сертифікатами X.509 SignedXmlі COSE. Підтримка SHA-3 може розширитися в майбутньому залежно від підтримки платформи та стандартів, які використовують SHA-3.

 

SHA-3 був стандартизований NIST як FIPS 202 як альтернатива, а не наступник SHA-2. Розробники та організації повинні вирішити, коли й навіть чи підходить їм прийняття SHA-3.

SDK: продуктивність і сумісність публікації контейнерів

Ми внесли кілька змін до стандартних значень створених зображень для програм .NET 8.


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

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


Ми покращили продуктивність надсилання контейнерів до віддалених реєстрів, надійність операції надсилання та підтримку більшого діапазону реєстрів. У той же час Том Десейн з Red Hat був зайнятий вдосконаленням нашої підтримки для ряду поширених реалізацій контейнерів.


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


Як побічний ефект цих змін ми також розширили нашу матрицю підтримки для реєстрів. Harbor і Artifactory приєдналися до списку відомих працюючих реєстрів, а робота Тома також уможливила запуск Quay.io і Podman.

 

Режим HybridGlobalization на WASM

 

Програми WASM можуть використовувати новий режим глобалізації, який полегшує пакет ICU та натомість використовує веб-API. У гібридному режимі дані глобалізації частково витягуються з пакета ICU, а частково – із викликів у JS. Він обслуговує всі регіони, які підтримує WASM .

 

Коли розглядати можливість використання HybridGlobalization

 

Цей параметр найбільше підходить для програм, які не можуть працювати в режимі InvariantGlobalization та використовувати дані локалізації з кількох сегментів ICU (EFIGS, CJK, no-CJK), тому наразі використовується:

у Blazor WebAssembly або

у браузері WASM.

Програми, які завантажували no-CJK або CJK shard за допомогою спеціального методу завантаження файлу ICU :
також може бути цікаво, тому що гібридний файл менший за фрагмент без CJK на 26% і менший за CJK на 15%.

Як використовувати HybridGlobalization

Установіть властивість MsBuild: <HybridGlobalization>true</HybridGlobalization>. Він завантажить файл icudt_hybrid.dat, який на 46% менший, ніж початково завантажений icudt.dat.

Обмеження

Через обмеження веб-API не всі API глобалізації підтримуються в гібридному режимі. Деякі з підтримуваних API змінили свою поведінку. Щоб переконатися, що це не вплине на вашу програму, прочитайте розділ Поведінкові відмінності для WASM .


API, які отримують результат шляхом звернення до JS, мають гіршу продуктивність, ніж негібридна версія. Ці API перераховані в документації . Інтерфейси API, яких немає в списках «Уражені публічні API», працюють так само, як і в негібридному режимі.

 

Підтримка націлювання на платформи iOS за допомогою NativeAOT

Тепер ми маємо підтримку націлювання на iOS-подібні платформи за допомогою Native AOT. Сюди входить створення й запуск програм .NET iOS, .NET MAUI а також NativeAOT з такими системами: ios, iossimulator, maccatalyst, tvos або tvossimulator. Мотивація цієї роботи полягає в тому, щоб дозволити користувачам вивчити можливість досягнення кращої продуктивності та економії розміру при орієнтації на такі платформи за допомогою. 

 

Ця функція доступна як додаткова функція, призначена для розгортання програми, коли Mono все ще використовується як вибір середовища виконання за умовчанням для розробки та розгортання програми. Ця віха була досягнута завдяки чудовій співпраці між членами нашої спільноти: @filipnavara @AustinWise та @am11 , які зробили внесок своєю роботою та спільними зусиллями NativeAOT, Mono і Xamarin команд.

Поточний стан

Поточний стан перевірено за допомогою:

.NET iOS app( )dotnet new ios

.NET MAUI iOS app( )dotnet new maui

 

Ці зразки програм показують такі попередні результати порівняно з Mono:

Результати .NET 8 Preview 6  (позначені як *-p6) показують, що .NET iOS app має значні покращення порівняно з Mono, де пакет стисненого додатка (.ipa) досяг на ~39% меншого розміру, демонструючи великий потенціал, тоді як .NET MAUI iOS app показує гірші результати, створюючи на ~13% гірший результат. Однак ми визначили основну причину регресії розміру за допомогою програми .NET MAUI, і наразі ми працюємо над таким списком проблем, щоб усунути регресію розміру:

1. https://github.com/xamarin/xamarin-macios/pull/18532

2. https://github.com/xamarin/xamarin-macios/issues/18479 

3. https://github.com/dotnet/runtime/issues/87924 

4. https://github.com/dotnet/runtime/issues/86649 

Ми оцінили, що усунувши виявлені проблеми 1-3), NativeAOT може досягти чудових результатів із додатком .NET MAUI, який показано в стовпці NativeAOT-fix, де розмір пакета додатків менший на  ~30%  порівняно з Mono. Виправлення проблеми 4) може ще більше покращити продуктивність, але на даному етапі ми не можемо оцінити точні цифри. Більше інформації про продуктивність .NET MAUI з NativeAOT відстежується на: https://github.com/dotnet/runtime/issues/80907

Відзначимо, що висновки щодо продуктивності NativeAOT на iOS-подібних платформах не слід робити ні з наведених у таблиці чисел, ні з випуску .NET 8 Preview 6 в цілому. Тим паче, що це все ще триває і це лише перший крок до того, щоб зробити функцію готовою до офіційного випуску .NET 9. Тому ми активно працюємо над удосконаленнями та визначаємо всю роботу, яка намагатиметься надати нашим клієнтам повний досвід NativeAOT для досягнення високої продуктивності та економії розміру, що відстежується в наведеному нижче списку проблем (та їхніх підзавдань):

– https://github.com/dotnet/runtime/issues/80905 tracks: Загальний прогрес

– https://github.com/xamarin/xamarin-macios/issues/17339 tracks: покращення інтеграції Xamarin

 

– https://github.com/dotnet/runtime/issues/86649 tracks: Покращення сумісності з обрізанням і розширеннями=

 

Як створити та запустити програму .NET MAUI за допомогою NativeAOT на пристрої iOS із .NET CLI

Встановлення

Створення образу програми

Вибір NativeAOT замість Mono

Властивості MSBuild PublishAot=true і PublishAotUsingRuntimePack=true (тимчасові, див. нижче) дозволяють розгортання NativeAOT.

Ці дві властивості є єдиною помітною відмінністю в порівнянні з розгортанням за допомогою Mono. Вам потрібно додати їх у PropertyGroup файлу проєкту вашої програми:

Це означає, що щоразу, коли програму розгортають через dotnet publish, вона розгортатиметься за допомогою NativeAOT.

Запуск програми

Сумісність з iOS і NativeAOT

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

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

– Встановлення та розгортання програми за допомогою Visual Studio ще не перевірено

Використання NativeAOT ввімкнено лише під час розгортання програми dotnet publish

Функціональні можливості бібліотеки Linq.Expressions ще не повністю підтримуються

Властивість MSBuild PublishAotUsingRuntimePack=true — це тимчасовий обхідний шлях, необхідний для націлювання на iOS-подібні платформи за допомогою NativeAOT 

Ця вимога стане неактуальною після виправлення: https://github.com/dotnet/runtime/issues/87060

Налагодження керованого коду підтримується лише з Mono

 

ПРИМІТКА. Попередній список є розширенням обмежень, які застосовуються до всіх платформ NativeAOT: https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/limitations.md

Резюме

.NET 8 Preview 6 містить захоплюючі нові функції та вдосконалення, які були б неможливі без наполегливої ​​роботи та відданості різноманітної команди інженерів Microsoft і пристрасної спільноти відкритих програм. Ми хочемо висловити нашу щиру подяку всім, хто зробив внесок у .NET 8 до цього часу , чи то через внески коду, звіти про помилки чи надання відгуків.

 

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

 

Source




Posted on 9. July 2023

У .NET Community Toolkit 8.2.1 з’явилися покращені генератори вихідного коду та засоби виправлення коду!

 

Ми раді повідомити про офіційний запуск версії 8.2.1 .NET Community Toolkit! Ця нова версія містить багато покращень QoL у всіх бібліотеках, ще кілька оптимізацій продуктивності для генераторів джерел MVVM Toolkit, нові засоби виправлення коду та покращену діагностику тощо!


.NET Community Toolkit 8.2.1

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

Що входить до складу .NET Community Toolkit?

.NET Community Toolkit містить такі бібліотеки:

CommunityToolkit.Common

CommunityToolkit.Mvvm(він же «Microsoft MVVM Toolkit»)

CommunityToolkit.Diagnostics

CommunityToolkit.HighPerformance

Щоб дізнатися більше про історію .NET Community Toolkit, ось посилання на нашу попередню публікацію оголошення про 8.0.0 .

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

Новий аналізатор і коректор коду для[RelayCommand] 

Атрибут [RelayCommand] (див. документацію тут) може автоматично обробляти асинхронні методи, і в цьому випадку він використовуватиме інтерфейси IAsyncRelayCommand (разом із відповідним типом асинхронної команди). Однак розробникам було нелегко виявити цю функцію, і багато хто натомість створював свої командні методи. Це також означало, що вони не могли використовувати всю додаткову функціональність, надану асинхронними командами (наприклад, звітування про прогрес і контроль паралельності).

Щоб допомогти з цим, версія 8.2.1 MVVM Toolkit постачається з абсолютно новим аналізатором, який випромінює діагностику для методів async void , позначених [RelayCommand]. А щоб зробити роботу ще простішою, є також новий засіб виправлення коду, який автоматично перероблятиме код за вас — просто клацніть піктограму лампочки, і дозвольте Roslyn зробити роботу за вас!

Виправлення коду аналізатора MVVM Toolkit

 

Тут ви можете побачити нову згенеровану діагностику, яка відображається для методу async void, пов’язаного з командою, і відповідного інтерфейсу коректора коду у Visual Studio з попереднім переглядом змін. Він також автоматично додасть необхідний оператор using у верхній частині вашого файлу, якщо Task ще немає в області видимості. І так само, як і інші засоби виправлення коду в MVVM Toolkit, ви також можете легко застосувати його до всіх місць у всьому вашому проєкті чи рішенні одним клацанням миші!

Інші зміни та вдосконалення

Виправлено аварійну ситуацію при індексації розрізаного екземпляра Memory2D<T> (#675): у деяких випадках могло бути викликано порушення доступу під час індексування елементів після нарізання екземпляра Memory2D<T>. Тепер це виправлено, дякуємо mahalex за повідомлення про це!

– Виправлено атрибути пересилання з від'ємними значеннями переліку (#681): використання елементів переліку з від’ємними значеннями більше не спричиняє проблеми з генераторами MVVM Toolkit для згенерованих спостережуваних властивостей. Дякуємо n-coelho-cerinnov за повідомлення про це!

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

Виправлення генератора  ObservableValidator для виявлення успадкованих властивостей (#616): генератор для перевірки властивостей більше не буде випадково ігнорувати властивості базових типів для цільової моделі перегляду. Дякуємо dgellow за повідомлення про це!

Додано попередження під час використання packages.config для MVVM Toolkit (#695): генератори набору інструментів MVVM працюють лише під час використання <PackageReference>(це відоме обмеження SDK, і воно є задумом), але раніше не було чітких вказівок на те, чому генератори не працювали для користувачів, які намагаються використовувати їх із проекту за допомогою packages.config. MVVM Toolkit тепер постачається з покращеною діагностикою, яка створить корисне попереджувальне повідомлення в цьому випадку. Дякуємо, smaugbend , що повідомили про це!

Частіше перевіряйте скасування в генераторах (#703): це має призвести до невеликих покращень у чутливості IDE під час використання MVVM Toolkit.

 

Видалення непотрібного тимчасового розподілу масиву (#719): ще одна невелика оптимізація пам’яті для генераторів джерел MVVM Toolkit.

Обробка поля [ObservableProperty] з ідентифікаторами ключових слів (#710): генератор більше не створюватиме недійсний код у випадку, якщо поля анотовані [ObservableProperty] використовують ідентифікатори ключових слів, які були екрановані у джерелі (наприклад, @event). Дякуємо Get0457 за повідомлення про це!

 

Примітка: існує відома проблема з джерельними генераторами в старіших версіях Roslyn, через яку IntelliSense іноді може не працювати належним чином для згенерованих учасників (див. #493 і пов’язану проблему відстеження Roslyn). Це нарешті виправлено у VS 2022 17.7, який зараз знаходиться в прев’ю. Якщо ви бачите будь-які проблеми під час використання MVVM Toolkit, обов’язково спробуйте останню версію VS 17.7 Preview!

Інші зміни

Ви можете переглянути повний журнал змін для цього випуску на сторінці випуску GitHub .

Почніть сьогодні!

Ви можете знайти весь вихідний код у нашому репо GitHub , деякі рукописні документи на MS learn і повні посилання на API на веб-сайті браузера .NET API. Якщо ви хочете внести свій внесок, не соромтеся відкривати питання або зв’язуватися з нами, щоб повідомити про свій досвід! Щоб стежити за розмовою в Twitter, використовуйте хештег #CommunityToolkit. Усі ваші відгуки дуже допомагають у формуванні напрямків цих бібліотек, тож поділіться ними!

 

Щасливого кодування!

Source




Posted on 30. April 2023

Анонсуємо .NET Community Toolkit 8.2! Покращена швидкість роботи генераторів, засоби для усунення помилок у коді, збільшення продуктивності та багато іншого!

 

 

Ми раді повідомити про офіційний запуск версії 8.2 інструментарію .NET Community Toolkit! Ця нова версія містить покращення швидкості роботи як під час виконання, так і в генераторах вихідного коду MVVM Toolkit, нові засоби для усунення помилок, що підвищують вашу результативність, нові функції на основі запитів користувачів та багато іншого!

.NET Community Toolkit 8.1.0 Preview 1

Що входить до інструментарію .NET Community Toolkit? 👀

Інструментарій .NET Community Toolkit містить наступні бібліотеки:

  • CommunityToolkit.Common

  • CommunityToolkit.Mvvm (також відомий як "Microsoft MVVM Toolkit")

  • CommunityToolkit.Diagnostics

  • CommunityToolkit.HighPerformance

Ці компоненти також широко використовуються в деяких програмах для роботи з вхідними повідомленнями, які постачаються з Windows, зокрема у Microsoft Store і програма "Photos"! 🚀

Для більш детальної інформації про історію розвитку інструментарію .NET Community Toolkit, ось посилання на попередній пост з анонсом версії 8.0.0.

 

Перелік основних змін, які включені в нову версію 8.2 інструментарію .NET Community Toolkit.

Користувацькі атрибути для [RelayCommand] 🤖

Продовжуючи роботу, виконану у випуску 8.1.0, і як було запропоновано на GitHub, новий випуск 8.2.0 набору інструментів MVVM Toolkit містить підтримку користувацьких атрибутів при використанні [RelayCommand]. Знову ж таки, було використано нативне field: і property: C#, щоб вказати цільові значення користувацьких атрибутів. Завдяки цьому ви тепер маєте повний контроль над атрибутами для всіх згенерованих членів, коли використовуєте [RelayCommand] для створення команди MVVM.

Наприклад, це особливо корисно, коли ви використовуєте модель подання, яка має підтримувати серіалізацію JSON, і вам потрібно явно ігнорувати згенеровану властивість. Ви можете використовувати підтримку нового  field: і property: наступним чином:

Після цього будуть створені наступні елементи:

Як і слід було очікувати, згенерована властивість DoWorkCommand має вказаний атрибут над нею! І, звичайно ж, підтримуються атрибути з будь-якою кількістю конструкторів та іменованих параметрів. Ви також можете використовувати просто field:, property:  поле:або будь-яку їх комбінацію 🙌

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

Нові змінені перехоплення [ObservableProperty] ⚗️

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

Раніше це був сценарій, де використання [ObservableProperty] не було ідеальним, оскільки воно не мало необхідної інфраструктури, щоб легко впровадити таку логіку для виконання необхідних змін стану для старих і нових значень, що встановлюються. Щоб виправити це, починаючи з версії 8.2 MVVM Toolkit, для всіх полів [ObservableProperty] генеруються два нові змінені перехоплення властивостей.

 

Наприклад, розглянемо наступний код:

Тепер буде згенеровано такий код:

Зверніть увагу на два нові методи "OnPropertyNameChanging" і "Changed", що генеруються, тепер вони також приймають попереднє значення. Ці два методи є простими у використанні перехопленнями для додавання коду, який спрацьовує при кожній події зміни властивості й може змінювати як старе, так і нове значення, що встановлюється. Наприклад, ви можете використовувати їх наступним чином:

І це все, що вам потрібно! Вибрана модель перегляду тепер завжди буде коректно повідомлятися як вибрана. Вам більше не потрібно повертатися до використання ручної властивості у подібних сценаріях, [ObservableProperty] тепер має вбудовану підтримку і для цього! 🪄

Примітка: MVVM Toolkit автоматично визначить, чи використовуєте ви будь-який з цих методів, щоб максимально оптимізувати кодову структуру. Крім того, виклики методів, які не реалізовані, будуть просто видалені компілятором Roslyn, тому вся ця функція є повністю платною!

Фіксери коду MVVM Toolkit 📖

У попередньому випуску MVVM Toolkit було додано два нових діагностичних аналізатора, які видають попередження при некоректному доступі до поля, позначеного [ObservableProperty], а також при оголошенні типу з [ObservableProperty] і подібними атрибутами, коли доступне використання наслідування. У версії 8.2 ці два аналізатори також містять вбудовані засоби для виправлення коду!

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

MVVM Toolkit analyzer code fix

Тут ви можете побачити новий інтерфейс виправлення коду у Visual Studio з попереднім переглядом змін, а також опціями застосування виправлення до потрібного вам діапазону

Оптимізація генератора вихідного коду MVVM Toolkit 🛫

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

  • Перенесено решту діагностик до аналізаторів (#581): ще дві діагностики з MVVM Toolkit було перенесено до діагностичного аналізатора, який можна запускати паралельно та поза процесом. Це вилучає деякі символи Roslyn з інкрементального конвеєра та покращує загальну продуктивність генератора.

  • Попередня обробка символів на початку роботи аналізаторів (#587): усі необхідні символи аналізатора тепер обробляються під час початкового налаштування зворотного виклику, що пришвидшує його виконання у кожному екземплярі компіляції.

Інші зміни та покращення 🚀

  • Виправлено помилку збірки з VB.NET проєктів (#592): MVVM Toolkit спричиняв помилки збірки з VB.NET проєктів через деякі некоректні властивості MSBuild. Наразі це виправлено.

  • Виправлено перенаправлені параметри подвійних атрибутів (#603): перенаправлені атрибути через [ObservableProperty] некоректно відображали цілі значення типів float та double у тип int. Тепер вони передаватимуться коректно зі збереженням початкового типу.

  • Виправлено генератори вихідного коду, що обробляють вкладені/загальні типи (#606): виправлено проблему, яка призводила до збою декількох генераторів вихідного коду при використанні Roslyn 4.0 та загальних типів.

  • Додано API ArrayPoolBufferWriter<T>.DangerousGetArray() (#616): цей новий API дозволяє легко взаємодіяти між ArrayPoolBufferWriter<T> та старими API, які вимагають масив T[] як параметр (на відміну від Span<T>/Memory<T>).

  • Вилучено System.Linq з CommunityToolkit.Diagnostics (#622): за результатами дослідження, проведеного у runtime/#82607, з пакунка Diagnostics повністю вилучено всі посилання на System.Linq. Це покращує підтримку обрізання у збірці та дозволяє заощаджувати більший розмір двійкових файлів у опублікованих збірках (особливо з NativeAOT).

  • Підтримка часткових методів з [RelayCommand] (#633): атрибут [RelayCommand] тепер працюватиме коректно, якщо його буде додано над визначенням або частиною реалізації часткового методу.

  • Додано підтримку відкритих узагальнених типів у ToTypeString (#639): розширення Type.ToTypeString() тепер коректно обробляє відкриті узагальнені типи. Наприклад, typeof(List<>).ToTypeString() тепер повертатиме "System.Collections.Generic.List<>".

  • Додано [MemberNotNull] у встановлювачах [ObservableProperty] (#646): коли це застосовано (тобто коли атрибут є доступним і тип властивості не можна занулити), генератор [ObservableProperty] також генеруватиме необхідні анотації про можливість занулення, щоб гарантувати, що встановлення створеної властивості коректно позначить поля як ініціалізовані. Це розв'язує проблему полів, які показували попередження про недопустимість, навіть якщо згенеровану властивість було встановлено.

  • Повні XML-документи для згенерованих членів (#653): усі згенеровані типи та члени тепер оформлено у вигляді повних XML-документів, тож перевірка коду, створеного генераторами вихідного коду MVVM Toolkit, має бути дещо простішою, ніж раніше.

Примітка: у старих версіях Roslyn існує відома проблема з генераторами вихідних кодів, через яку IntelliSense може іноді працювати некоректно для згенерованих елементів (див. #493 і пов'язану з ним проблему відстеження у Roslyn). Ця проблема має бути в основному виправлена в VS 2022 17.6 і вище (або, коли використовується Roslyn 4.6, в тому числі через інші IDE, такі як VS Code і Rider). Якщо ви зіткнулися з цією проблемою, переконайтеся, що ви оновили свій інструментарій до останньої доступної версії.

Інші зміни ⚙️

Ви можете переглянути повний список змін до цього випуску на сторінці релізу на GitHub.

Почніть вже сьогодні! 🎉

Ви можете знайти весь вихідний код у репозиторії GitHub, деякі рукописні документи на MS learn та повні посилання на API на вебсайт браузера .NET API. Якщо ви хочете зробити свій внесок, не соромтеся залишати проблеми або звертатися до команди, щоб повідомити про свій досвід! Щоб стежити за обговоренням у Twitter, використовуйте хештег #CommunityToolkit. Всі ваші відгуки дуже допомагають формувати напрямок розвитку цих бібліотек, тому обов'язково діліться ними!

 

Вдалого кодування! 💻