Posted on 4. April 2024

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

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

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

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

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

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

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

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

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

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

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

Як оновити

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

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

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

Enable .NET 8 in Visual Studio 2022 for Mac

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

dotnet workload install maui


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

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

 

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

Source



Posted on 10. December 2023

.NET 8 Networking Improvements

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

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


HTTP

Метрики

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

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

-void Redirect();

 

+void Redirect(string redirectUri);

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

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

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

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

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


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

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

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

 

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

HttpClientFactory

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

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

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

 

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

 

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

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

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

 

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

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

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

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

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

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

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

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

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

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

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

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

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

 

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

Консольний вивід логу за замовчуванням HttpClientFactory виглядає так:

Зауважте, що для перегляду повідомлень рівня Trace вам потрібно ввімкнути це у файлі конфігурації глобального логування або за допомогою SetMinimumLevel(LogLevel.Trace). Але навіть враховуючи лише Informational повідомлення, «старе» логування все одно має 4 повідомлення на запит.

 

Щоб видалити стандартне (або раніше додане) логування, ви можете використати новий метод розширення RemoveAllLoggers(). Він особливо потужний у поєднанні з API ConfigureHttpClientDefaults, описаним у розділі «Налаштування параметрів за замовчуванням для всіх клієнтів» вище. Таким чином ви можете видалити «старе» журналювання для всіх клієнтів одним рядком:

Якщо вам колись знадобиться повернути «старе» логування, наприклад, для певного клієнта, ви можете зробити це за допомогою AddDefaultLogger().


Додати спеціальне логування

Окрім можливості видаляти «старе» логування, нові API HttpClientFactory також дозволяють повністю налаштувати логування. Ви можете вказати, що та як реєструватиметься, коли HttpClient починає запит, отримує відповідь або створює виняток.

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


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

 

Реєстрація:

Приклад імплементації логера:

Зразок результату:

Об’єкт контексту запиту

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

Якщо об’єкт контексту не потрібен, імплементація може повернути null з LogRequestStart.

 

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

Уникайте читання з потоків вмісту

Якщо ви збираєтеся читати та логувати,  наприклад, вміст запиту та відповіді, майте на увазі, що це потенційно може мати несприятливий побічний ефект для роботи кінцевого користувача та викликати помилки. Наприклад, вміст запиту може бути використано до того, як його буде надіслано, або вміст відповіді величезного розміру може бути буферизовано в пам’яті. Крім того, до .NET 7 доступ до заголовків не був потоково безпечним і міг призвести до помилок і неочікуваної поведінки.

Використовуйте асинхронне логування з обережністю

Ми очікуємо, що синхронний інтерфейс IHttpClientLogger підійде для переважної більшості випадків використання спеціального логування. Рекомендується утримуватися від використання асинхронного протоколу з міркувань продуктивності. Однак, якщо суворо потрібен асинхронний доступ до логування, ви можете застосувати асинхронну версію IHttpClientAsyncLogger. Він походить від IHttpClientLogger, тому може використовувати той самий API AddLogger для реєстрації.

Зауважте, що в такому випадку слід також реалізувати аналоги синхронізації методів логування, особливо якщо реалізація є частиною бібліотеки, орієнтованої на .NET Standard або .NET 5+. Відповідники синхронізації викликаються з методів синхронізації HttpClient.Send; навіть якщо поверхня .NET Standard їх не містить, бібліотеку .NET Standard можна використовувати в програмі .NET 5+, щоб кінцеві користувачі мали доступ до методів синхронізації HttpClient.Send.

Обгортання та не обгортання логерів

Коли ви додаєте логер, ви можете явно встановити параметр wrapHandlersPipeline, щоб вказати, чи буде логер

 

– обгортати пайплайн обробників (додано до верхньої частини пайплайну, що відповідає повідомленням № 1, 2, 7 і 8 у розділі «Огляд старого логування» вище)

 

або не обгортати пайплайн обробників (додано внизу, що відповідає повідомленням № 3, 4, 5 і 6 у розділі «Огляд старого логування» вище).

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


Різниця між обгортанням і не обгортанням пайплайну є найбільш помітною у випадку додавання до пайплайну обробника повторних спроб (наприклад, Polly або іншої користувацької реалізації повторних спроб). У цьому випадку логер з обгортанням (у верхній частині) буде реєструвати повідомлення про один успішний запит, а час, що минув, буде загальним часом від моменту, коли користувач ініціював запит, до моменту отримання ним відповіді. Логер без обгортання (внизу) реєстрував би кожну ітерацію повторної спроби, причому перші ітерації могли б містити виняток або код невдалої спроби, а остання - успішний результат. Час, що минув у кожному випадку, був би часом, витраченим виключно на первинний обробник (той, що фактично надсилає запит по дроту, наприклад, HttpClientHandler)).

Це можна проілюструвати наступними діаграмами:


– Кейс з обгортанням ( wrapHandlersPipeline=TRUE)

Кейс без обгортання (wrapHandlersPipeline=FALSE)

Спрощена конфігурація SocketsHttpHandler

.NET 8 додає більш зручний і плавний спосіб використання SocketsHttpHandler як основного обробника в HttpClientFactory (dotnet/runtime#84075)

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

 

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

}

QUIC

Підтримка OpenSSL 3

Більшість поточних дистрибутивів Linux прийняли OpenSSL 3 у своїх останніх випусках:

– Debian 12+: Bookworm OpenSSL

– Ubuntu 22+: Jammy OpenSSL

– Fedora 37+: Fedora OpenSSL

– OpenSUSE: Tumbleweed OpenSSL

– AlmaLinux 9+: репозиторій пакетів AlmaLinux 9


Підтримка QUIC .NET 8 готова до цього (dotnet/runtime#81801).


Першим кроком для досягнення цього було переконатися, що MsQuic, реалізація QUIC, яка використовується нижче System.Net.Quic, може працювати з OpenSSL 3+. Ця робота відбулася в репозиторії MsQuic microsoft/msquic#2039. Наступним кроком було переконатися, що пакет libmsquic створено та опубліковано з відповідною залежністю від версії OpenSSL за замовчуванням для конкретного дистрибутива та версії. Наприклад, дистрибутив Debian:

– Debian 11 libmsquic залежить від OpenSSL 1.1

– Debian 12 libmsquic залежить від OpenSSL 3


Останнім кроком було переконатися, що тестуються правильні версії MsQuic і OpenSSL і що тести охоплюють усі дистрибутиви, що підтримуються .NET.


Винятки

Після публікації QUIC API у .NET 7 (як функція попереднього перегляду) ми отримали кілька проблем щодо винятків:

dotnet/runtime#78751 : QuicConnection.ConnectAsync генерує виключення SocketException, коли хост не знайдено

dotnet/runtime#78096: QuicListener AcceptConnectionAsync і OperationCanceledException

dotnet/runtime#75115: QuicListener.AcceptConnectionAsync повторне виключення


У .NET 8 поведінку винятків System.Net.Quic було повністю переглянуто в dotnet/runtime#82262 і вирішено вищезгадані проблеми.

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

QuicException: усі помилки, характерні для протоколу QUIC або пов’язані з його обробкою.

- З’єднання закрито локально або одноранговим вузлом.

- Підключення перервано через бездіяльність.

- Потік перервано локально або партнером.

- Інші помилки, описані в QuicError


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

- Адреса вже використовується.

- Цільовий хост не доступний.

- Вказана адреса недійсна.

- Неможливо визначити ім’я хоста.


AuthenticationException: для всіх питань, пов’язаних із TLS. Мета полягає в тому, щоб мати таку ж поведінку, як SslStream.

- Помилки, пов’язані із сертифікатом.

- Помилки узгодження ALPN.

- Скасування користувачем під час рукостискання.


ArgumentException: коли надані  QuicConnectionOptions або QuicListenerOptions недійсні.

- Надані обмеження потоку не входять у діапазон 0-65535.

- Пропущення обов’язкових властивостей, таких як: DefaultCloseErrorCode або DefaultStreamErrorCode.

- Невизначеність ClientAuthenticationOptions або ServerAuthenticationOptions.

 

OperationCanceledException: щоразу коли CancellationToken отримує скасування.

ObjectDisposedException: кожного разу, коли викликається метод на вже видаленому об’єкті.

Зауважте, що наведені вище приклади не є вичерпними.


Крім зміни поведінки, змінилася також QuicException. Однією з цих змін було коригування значень enum QuicError. Елементи, які зараз охоплюються, SocketException було видалено, і додано нове значення для помилок зворотного виклику користувача (dotnet/runtime#87259). Нещодавно доданий CallbackError використовується для того, щоб відрізнити винятки, створені, QuicListenerOptions.ConnectionOptionsCallbac k від System.Net.Quic ( dotnet/runtime#88614). Отже, якщо користувацький код згенерує, наприклад, ArgumentException, QuicListener.AcceptConnectionAsync оберне його у QuicException  з QuicError , встановленим у CallbackError, а внутрішній виняток міститиме оригінальний виняток користувача. Це можна використовувати таким чином:

Останньою зміною в просторі винятків було додавання коду транспортної помилки до QuicException ( dotnet/runtime#88550). Коди транспортних помилок визначені RFC 9000 Коди транспортних помилок, і вони вже були доступні в System.Net.Quic MsQuic , просто вони не були оприлюднені. Отже, до QuicException: TransportErrorCode була додана нова властивість, яка може бути скасована. Ми хотіли б подякувати учаснику спільноти AlexRadch, який вніс цю зміну в dotnet/runtime#88614.

Сокети

Найвпливовішою зміною, зробленою в просторі сокетів, було значне зменшення розподілу для сокетів без підключення (UDP) (dotnet/runtime#30797). Одним із найбільших факторів розподілу під час роботи з UDP-сокетами було виділення нового об’єкта EndPoint (і підтримка виділень, таких як IPAddress) під час кожного виклику Socket.ReceiveFrom. Щоб пом’якшити це, натомість було введено набір нових API, які працюють із SocketAddress( dotnet/runtime#87397). SocketAddress внутрішньо зберігає IP-адресу як масив байтів у формі, що залежить від платформи, щоб її можна було безпосередньо передати до викликів операційної системи. Таким чином, жодних копій даних IP-адреси не потрібно робити перед викликом функцій власного сокета.

 

Крім того, нещодавно додані перевантаження ReceiveFrom-system-net-sockets-socketflags-system-net-socketaddress)) і ReceiveFromAsync-system-net-sockets-socketflags-system-net-socketaddress-system-threading-cancellationtoken)) не створюють новий екземпляр IPEndPoint під час кожного виклику, але радше змінюють наданий  параметр receivedAddress на місці. Усе це разом можна використати, щоб зробити код сокета UDP більш ефективним:

Крім того, було покращено роботу з SocketAddress dotnet/runtime#86872 . SocketAddress тепер має кілька додаткових учасників, які роблять його більш корисним самостійно:

– getter Buffer: для доступу до всього основного буфера адреси.

– setter Size: щоб мати можливість налаштувати вищезгаданий розмір буфера (тільки до меншого розміру).

– static GetMaximumAddressSize: щоб отримати необхідний розмір буфера на основі типу адреси.

interface IEquatable<SocketAddress>: SocketAddress можна використовувати для розрізнення однорангових пристроїв, з якими спілкується сокет, наприклад, як ключ у словнику (це не нова функція, вона просто робить її доступною через інтерфейс).

І, нарешті, деякі внутрішні копії даних IP-адреси були видалені, щоб підвищити продуктивність.

Мережеві примітиви

Типи MIME

Додавання відсутніх типів MIME було однією з найбільш популярних проблем у мережевому просторі (dotnet/runtime#1489). Це була здебільшого зміна, керована спільнотою, яка призвела до пропозиції API dotnet/runtime#85807 . Оскільки це доповнення потребувало проходження процесу перевірки API, необхідно було переконатися, що додані типи є релевантними та відповідають специфікації (IANA Media Types). За цю підготовчу роботу ми хотіли б подякувати учасникам спільноти Bilal-io та mmarinchenko .

IPNetwork

Ще одним новим доповненням до API в .NET 8 є новий тип IPNetwork (dotnet/runtime#79946). Структура дозволяє вказувати безкласові IP-підмережі, як визначено в RFC 4632. Наприклад:

127.0.0.0/8 для безкласового визначення, що відповідає підмережі класу А.

42.42.128.0/17 для безкласової підмережі з 2¹⁵ адресами.

2a01:110:8012::/100 для IPv6 підмережі з 2²⁸ адресами.

 

Новий API пропонує створення або з IPAddress та довжини префікса за допомогою конструктора, або шляхом розбору рядка за допомогою TryParse або Parse. Крім того, він дозволяє перевірити приналежність IPAddress до підмережі за допомогою методу Contains. Приклад використання може виглядати так:

Зауважте, що цей тип не слід плутати з класом Microsoft.AspNetCore.HttpOverrides.IPNetwork, який існував у ASP.NET Core з 1.0. Ми очікуємо, що API ASP.NET з часом перейдуть до нового типу System.Net.IPNetwork  (dotnet/aspnetcore#46157).


Завершальні примітки

Теми, вибрані для цієї публікації в блозі, не є вичерпним списком усіх змін, внесених у .NET 8, лише ті, про які, на нашу думку, можуть бути найцікавішими. Якщо ви більше зацікавлені в покращенні продуктивності, вам слід ознайомитися з розділом «Мережі» у величезній публікації блогу про продуктивність Стівена. А якщо у вас виникнуть запитання або знайдете будь-які помилки, ви можете зв’язатися з нами в репозиторії Dotnet/Runtime .

 

Source

 

 





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 20. November 2023

Announcing .NET MAUI in .NET 8

Анонс .NET MAUI у .NET 8

Сьогодні наша команда рада представити вам останній великий стабільний реліз .NET MAUI у .NET 8! Ми створюємо .NET MAUI, щоб дозволити розробникам .NET створювати крос-платформні додатки для Android, iOS, macOS і Windows із глибокою вбудованою інтеграцією, власними користувальницькими інтерфейсами та гібридними можливостями, які розширюють можливості Blazor та інших технологій вебінтерфейс користувача. Сьогодні відзначається третій великий реліз.NET MAUI за останні 18 місяців, який зміщує кут уваги від нашого об’єднання платформи Xamarin із .NET до просування .NET як єдиного цілого.


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


«Створення макетів справа наліво в .NET MAUI стало реальністю завдяки .NET 8. Візуальні елементи ідеально впорядковані, а каруселі тепер чудово працюють. Ми деякий час працювали з останніми версіями попереднього перегляду, і вдосконалення, зроблені командою MAUI, виявилися ключовими для успішної доставлення програм RTL нашим клієнтам». – Лео, UXDivers для Umrahme

справа наліво порівнює .net 8 і 7

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

Загальна якість

По-перше, дивлячись на реліз у цифрах, у .NET 8 ми маємо:

– Об’єднано 1618 pull requests (з 577)

– Вирішено 689 помилок (зі 180)


Порівняно з релізом .NET 7 GA це на 180% більше пулл реквестів та на 283% більше вирішених проблем із помилками. Оскільки .NET 7 був коротшим релізом для .NET MAUI, я подумав, що було б цікаво також включити всі випуски служби .NET 7. Беручи це до уваги, .NET 8 усе ще має на 18% більше пулл реквестів та на 13% більше вирішених проблем із помилками.

Це було б неможливо без 94 чудових співавторів у командах Microsoft і особливо в спільноті. Від імені всіх користувачів .NET MAUI ми щиро дякуємо за ваш внесок і підтримку!

Учасники розробки .NET MAUI у .NET 8

На початку обслуговування .NET 7 ми чітко й голосно почули від розробників, що нам потрібно підвищити якість релізів, і тому ми зробили саме це, піднявши планку того, що ми будемо резервно портувати з нашої роботи .NET 8 для релізів .NET 7 до у нас було більше автоматизованого тестування та інших процесів, щоб краще захиститися від цього. Під час наступних випусків ми ввімкнули неактивний набір тестів Xamarin.Forms для запуску в .NET і з .NET MAUI, а також додали понад 3500 тестів пристроїв у Windows, розповсюджених у областях Controls, Core і Essentials серед інших тестів.


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

Основні сфери покращення якості:

– Поведінка клавіатури, особливо на мобільних пристроях

– Підтримка FlowDirection для мов із письмом справа наліво

– Точність компонування та продуктивність

– Продуктивність прокручування

– Управління пам'яттю


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

Що нового

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

Клавіатурні прискорювачі

 

Прискорювач клавіатури – це комбінація клавіш, яку можна пов’язати з будь-яким пунктом меню в настільній програмі, наприклад копіювати (Ctrl+C), вставити (Ctrl+V) і вирізати (Ctrl+X).

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

Покращення жестів вказівника

.NET MAUI деякий час містив PointerGesture, щоб ви знали, коли курсор знаходиться над елементом, і тепер у .NET 8 ви отримуєте події PointerPressed та PointerReleased з аргументами подій, що містять більше інформації про положення вказівника. Це працює на Android, iPadOS, Mac Catalyst і Windows.


Перегляньте приклад у відеоплеєрі


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

Покращення жестів перетягування

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

Перегляньте приклад у відеоплеєрі

Перегляньте інший приклад у відеоплеєрі

Перегляньте оновлену документацію щодо жестів перетягування та опускання.

Покращення продуктивності та пам'яті

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

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

Різні моменти

З огляду на величезний обсяг зусиль, які були витрачені на створення цього релізу, не дивно, що є ще набагато більше того, що потрібно висвітлити. Щоб отримати повний перелік змін, прочитайте докладні примітки до випуску .NET MAUI 8.0.3 , а для скороченого підсумку насолодіться читанням: Що нового в .NET MAUI для .NET 8.

Опублікуйте незапаковану програму .NET MAUI для Windows за допомогою CLI .

– Використовуйте ContentPage.HideSoftInpuOnTapped, щоб закрити клавіатуру під час торкання будь-де на сторінці

– Елементи керування, які підтримують введення тексту, отримують методи розширення, які підтримують приховання та показ клавіатури програмного введення. Щоб отримати додаткові відомості, див. Приховати та показати програмну клавіатуру введення .

– WebView отримує властивість UserAgent. Для отримання додаткової інформації див. WebView .

– Вбудоване медіа-відтворення відео HTML5, включаючи автоматичне відтворення та картинку в картинці, увімкнено за замовчуванням для WebView на iOS. Додаткову інформацію див. у розділі Налаштування параметрів відтворення медіа на iOS і Mac Catalyst .

– BlazorWebView отримує властивість StartPath, метод TryDispatchAsync і розширені можливості логування. Щоб отримати додаткові відомості, перегляньте розділ Розміщення веб-програми Blazor у програмі .NET MAUI за допомогою BlazorWebView .

– Клас TapGestureRecognizer отримує можливість обробляти вторинні натискання на Android. Додаткову інформацію див. у розділі Розпізнавання жесту дотику .

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

.NET MAUI та .NET 8 включено в сьогоднішній стабільний реліз Visual Studio 2022 17.8 .

На всіх платформах ви можете розробляти з .NET MAUI за допомогою Visual Studio Code. Установіть розширення .NET MAUI і повідомте нам, як ми можемо покращити цей попередній перегляд для вас у майбутньому.


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

Через припинення використання Visual Studio для Mac наступного року ви зможете продовжувати розробку за допомогою Visual Studio для Mac після ввімкнення функції попереднього перегляду для .NET 8 у параметрах.

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

Дякую

 

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




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 17. November 2023

Announcing ASP.NET Core in .NET 8

Анонс ASP.NET Core в .NET 8


ASP.NET Core у .NET 8 — це комплексне рішення для сучасної веброзробки. Він задовольняє всі ваші потреби в веброзробці від фронтенду до бекенду. За допомогою Blazor, а також високопродуктивних внутрішніх API, і сервісів, які є надійними і безпечними, ви можете створювати красиві, насичені та інтерактивні вебдодатки.  ASP.NET Core у .NET 8 ідеально підходить для створення хмарних додатків, а чудові інструменти у Visual Studio та Visual Studio Code підвищують вашу продуктивність. Завдяки ASP.NET Core у .NET 8 кожен розробник є розробником повного стека!


.NET 8 тепер доступний – оновіть свої проєкти ASP.NET Core сьогодні!

Починаймо

Щоб розпочати роботу з ASP.NET Core у .NET 8, інсталюйте .NET 8 SDK . .NET 8 також входить до складу Visual Studio 2022 і підтримується у Visual Studio Code з C# Dev Kit.


Якщо ви новачок у ASP.NET Core, ви можете розпочати навчання, перейшовши на https://asp.net і ознайомившись із можливостями ASP.NET Core.

Що нового?

Давайте розглянемо деякі чудові нові функції та вдосконалення, доступні в ASP.NET Core у .NET 8.


Продуктивність

ASP.NET Core у .NET 8 — це найшвидший реліз! Порівняно з .NET 7, ASP.NET Core у .NET 8 на 18% швидший за тестом Techempower JSON і на 24% швидший за тестом Fortunes:

Порівняння тестів Techempower .NET 7 і .NET 8

Ви можете прочитати все про покращення продуктивності ASP.NET Core у публікації блогу Бреннана Конроя « Покращення продуктивності в ASP.NET Core 8» .


Підтримка ASP.NET Core для нативного AOT

У .NET 8 ми представляємо власну підтримку AOT для ASP.NET Core, спочатку зосереджуючись на хмарних додатках API. Тепер можна опублікувати програму ASP.NET Core із власним AOT , створюючи автономну програму, яка завчасно (AOT) скомпільована до власного коду.

 

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

Переваги використання нативного AOT з ASP.NET Core

Публікація та розгортання нативної програми AOT може надати такі переваги:

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

Зменшення розміру виконуваного файлу може призвести до:

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

- Зменшення часу розгортання через менші образи.


Скорочений час запуску: нативні програми AOT можуть запускатися швидше, частково завдяки видаленню компіляції JIT. Скорочений запуск означає:

- Додаток готовий швидше обслуговувати запити.

- Покращене розгортання за допомогою оркестраторів контейнерів, які керують переходами від однієї версії програми до іншої.

– Зменшена потреба в пам’яті: програми ASP.NET Core, опубліковані як нативні AOT, можуть мати зменшені вимоги до пам’яті залежно від виконуваної роботи, оскільки вони ввімкнули новий режим DATAS GC за замовчуванням. Зменшення споживання пам’яті може призвести до більшої щільності розгортання та покращеної масштабованості.

Як приклад, ми запустили просту програму ASP.NET Core API у нашій лабораторії порівняльного аналізу, щоб порівняти відмінності в розмірі програми, використанні пам’яті, часу запуску та навантаженні ЦП, опублікованому з власним AOT і без нього:

Вид публікації

Час запуску (мс)

Розмір програми (МБ)

Робочий набір (Мб)

За замовчуванням

156

92.6

96

Нативний АОТ

48

10,0

41

Наведена вище таблиця показує, що публікація програми як нативної AOT значно покращує час запуску, розмір програми та використання пам’яті. Час запуску скорочено на 70%, розмір програми – на 89%, а використання пам’яті під навантаженням – на 57%!

Більш складний зразок програми API із методами CRUD-стилю, включаючи перевірку моделі, OpenAPI, автентифікацію JWT і авторизацію на основі політики, прив’язку конфігурації та присутність у базі даних PostgreSQL за допомогою Npgsql , вказує такі зміни в своїх показниках порівняно з нативним AOT:

Вид публікації

Час запуску (мс)

Розмір програми (МБ)

Робочий набір (Мб)

За замовчуванням

473

98,27

193

Нативний АОТ

115

21.55

121

Для цієї складнішої програми час запуску скорочено на 76%, розмір програми зменшено на 78%, а використання пам’яті під навантаженням – на 37% !

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


Сумісність ASP.NET Core та нативної AOT

Не всі функції в ASP.NET Core сумісні з нативним AOT. Подібним чином не всі бібліотеки, які зазвичай використовуються в ASP.NET Core, сумісні з нативним AOT. .NET 8 є початком роботи над реалізацією нативного AOT в ASP.NET Core, з початковим фокусом на підтримку додатків, що використовують мінімальні API або gRPC і розгортаються в хмарних середовищах. Нагадуємо, що в .NET 7 з’явилася підтримка нативної публікації AOT для консольних проєктів. Ваші відгуки допоможуть скерувати наші зусилля для майбутніх випусків, щоб переконатися, що ми зосереджуємось на тих місцях, де переваги нативної AOT можуть мати найбільший вплив.


Нативні додатки AOT постачаються з кількома основними вимогами сумісності. До ключових належать:

– Без динамічного завантаження (наприклад, Assembly.LoadFile)

– Немає генерації коду виконання через JIT (наприклад, System.Reflection.Emit)

– Немає C++/CLI

– Немає вбудованого COM (стосується лише Windows)

– Потрібна обрізка, яка має обмеження

– Передбачає компіляцію в один файл, який має відомі несумісності

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


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


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


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


У наведеній нижче таблиці підсумовано сумісність функцій ASP.NET Core із нативним AOT:

Особливість

Повністю підтримується

Частково підтримується

Не підтримується

gRPC

Повністю підтримується



Мінімум API


Частково підтримується


MVC



Не підтримується

Blazor



Не підтримується

SignalR



Не підтримується

Автентифікація JWT

Повністю підтримується



Інша автентифікація



Не підтримується

CORS

Повністю підтримується



Перевірки стану здоров'я

Повністю підтримується



Протоколювання Http

Повністю підтримується



Локалізація

Повністю підтримується



Кешування виводу

Повністю підтримується



Обмеження швидкості

Повністю підтримується



Запит на декомпресію

Повністю підтримується



Кешування відповідей

Повністю підтримується



Стиснення відповіді

Повністю підтримується



Перепишіть

Повністю підтримується



Сесія



Не підтримується

SPA



Не підтримується

Статичні файли

Повністю підтримується



WebSockets

Повністю підтримується



 

Ви можете переглянути поточні відомі проблеми щодо сумісності ASP.NET Core та рідної AOT у .NET 8 тут.


Під час створення програми зверніть увагу на попередження AOT . Коректна робота програми, яка видає попередження AOT під час публікації, не гарантується. Якщо ви не отримуєте жодних попереджень AOT під час публікації, ви повинні бути впевнені, що ваша програма працюватиме стабільно після публікації для AOT, як це було під час робочого процесу розробки F5 / dotnet run. Однак, все одно важливо ретельно перевірити свою програму під час переходу на власну модель розгортання AOT, щоб переконатися, що функціональні можливості, спостережувані під час розробки (коли програму не обрізано та скомпільовано за допомогою JIT), збережені у власному виконуваному файлі.


Мінімальні API та нативний AOT

Щоб зробити мінімальні API сумісними з нативним AOT, ми запровадили Генератор делегатів запитів (RDG) . RDG — це генератор вихідних кодів , який виконує роботу, подібну до RequestDelegateFactory(RDF) , перетворюючи різноманітні виклики MapGet(), MapPost()тощо у вашій програмі на RequestDelegate, пов’язані з указаними маршрутами, але замість того, щоб робити це в пам’яті вашої програми під час її запуску, він робить це під час компіляції та генерує код C# безпосередньо у вашому проєкті. Це видаляє генерацію цього коду під час виконання та гарантує, що типи, які використовуються у ваших API, зберігаються в коді вашої програми таким чином, що його можна статично проаналізувати власним ланцюжком інструментів AOT, гарантуючи, що необхідний код не буде обрізано. Ми працювали над тим, щоб більшість функцій Minimal API, якими ви сьогодні користуєтеся, підтримувалися RDG і, отже, сумісні з нативним AOT.

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

у файлі проєкту.

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

 

Мінімальні API оптимізовано для отримання та повернення корисних даних JSON за допомогою System.Text.Json, тому також застосовуються вимоги сумісності для JSON і рідного AOT. Це вимагає використання  System.Text.Json source generator . Усі типи, які приймаються як параметри для делегатів запитів або повертаються від делегатів запитів у ваших мінімальних API, мають бути налаштовані на JsonSerializerContext зареєстрованому за допомогою ін’єкції залежностей ASP.NET Core, наприклад:

gRPC і нативний AOT

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


Бібліотеки та нативний АОТ

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

 

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

Початок роботи з нативним розгортанням AOT в ASP.NET Core

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

– Деякі функції, несумісні з нативним AOT, вимкнено та створюють винятки під час виконання.

– Аналізатор вихідного коду ввімкнено, щоб виділяти код проєкту, який несумісний із нативним AOT. Під час публікації вся програма, включаючи пакети NuGet, на які посилаються, знову аналізується на сумісність.


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

Перш ніж публікувати проєкти .NET із власним AOT, потрібно встановити такі передумови.


На Windows інсталюйте Visual Studio 2022 і включіть робоче навантаження «Розробка робочого столу за допомогою C++» з усіма компонентами за замовчуванням.

Знімок екрана робочого навантаження «Розробка робочого столу за допомогою C++» у програмі встановлення Visual Studio 2022

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

 

– Ubuntu (18.04+)

– Alpine (3.15+)

Зауважте, що наразі кросплатформна власна публікація AOT не підтримується, тобто вам потрібно виконати публікацію на тому самому типі платформи, що й передбачувана ціль, наприклад, якщо розгортання націлено на Linux, виконайте публікацію на Linux. Контейнери Docker можуть бути зручним способом увімкнення кросплатформної публікації, приклад чого можна знайти в репозиторії dotnet-docker .


Власні програми AOT, опубліковані ASP.NET Core, можна розгортати та запускати будь-де, де можуть власні виконувані файли. Для цього популярним вибором є контейнери. Власні програми AOT, опубліковані .NET, мають ті самі вимоги до платформи, що й автономні програми .NET, і тому mcr.microsoft.com/dotnet/runtime-depsїх слід використовувати як базовий образ.


Нативні готові для AOT шаблони проєктів

Шаблони для створення проектів ASP.NET Core із нативним AOT у Visual Studio

У .NET 8 є два власних шаблони проєктів із підтримкою AOT, які допоможуть вам почати створювати програми ASP.NET Core за допомогою власного AOT.

Шаблон проєкту «ASP.NET Core gRPC Service» оновлено, щоб включити нову опцію «Увімкнути власну публікацію AOT», яка, коли вибрано, налаштовує новий проект для публікації як власної AOT. Це робиться шляхом налаштування <PublishAot>true</PublishAot> у файлі .csproj проєкту.


Існує також абсолютно новий шаблон проєкту «ASP.NET Core Web API (native AOT)», який створює проєкт, більш безпосередньо зосереджений на сценаріях, налаштованих на хмару, перш за все API. Цей шаблон попередньо налаштовано для власного AOT і відрізняється від наявного шаблону проєкту «Web API» таким чином:


– Використовує лише мінімальні API, оскільки MVC ще не сумісний з AOT

– Використовує нове API WebApplication.CreateSlimBuilder, щоб гарантувати, що за замовчуванням увімкнено лише основні функції, мінімізуючи розмір розгорнутої програми

– Налаштовано лише для прослуховування HTTP, оскільки трафік HTTPS зазвичай обробляється вхідною службою в хмарних розгортаннях

– Не включає профіль запуску для роботи під IIS або IIS Express

– Вмикає генератор джерела серіалізатора JSON

– Включає зразок «Todos API» замість зразка прогнозу погоди


Ви можете створити новий проєкт Web API, налаштований на публікацію як нативний AOT, використовуючи dotnet CLI:

Ось вміст Program.cs у проєкті, створеному за допомогою нового шаблону «ASP.NET Core Web API (native AOT)»:

Нативний заклик до дії AOT

Власне розгортання AOT підходить не для всіх програм, але в сценаріях, коли переваги, які пропонує нативний AOT, є переконливими, воно може мати величезний вплив. Хоча це лише початок, ми хотіли б, щоб ви спробували власну підтримку AOT для ASP.NET Core у .NET 8 і поділіться будь-яким відгуком, залишивши коментар тут або зареєструвавши проблему на GitHub . Обов'язково прочитайте поточні відомі проблеми щодо сумісності ASP.NET Core і рідної AOT.

У .NET 8 разом із функціями ASP.NET Core, описаними тут, автентифікацією JWT, перевіркою параметрів і доступом до даних ADO.NET для SQLite та PostgreSQL, усе було оновлено для сумісності з рідною AOT. Ми з нетерпінням чекаємо, що екосистема .NET продовжить використовувати більше бібліотек і функцій для нативного AOT.

Повний стек UI з Blazor

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

Blazor у .NET 8 тепер підтримує такі нові можливості:

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

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

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

Увімкнути інтерактивність для кожного компонента або сторінки: увімкніть інтерактивне відтворення на основі Blazor Server або Blazor WebAssembly для окремих компонентів або сторінок за допомогою нової директиви Razor – @rendermode. Ви платите лише за інтерактивність, як-от встановлення з’єднання WebSocket або завантаження середовища виконання .NET WebAssembly, де воно використовується.

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


Більше вбудованих компонентів і можливостей Blazor

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


Blazor тепер постачається з QuickGrid, швидким і функціональним компонентом сітки даних для обробки найпоширеніших потреб даних. QuickGrid може завантажувати строго типізовані дані з різноманітних джерел даних, включаючи Entity Framework Core, і ви можете швидко під'єднати QuickGrid до наявної моделі даних за допомогою нового скаффолдера Blazor CRUD. Він підтримує сортування, фільтрацію, сторінку та віртуалізацію. Перегляньте демонстраційний сайт QuickGrid , щоб побачити компонент у дії.


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


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

Покращення .NET WebAssembly

Виконання вашого коду .NET на WebAssembly з браузера значно покращено в .NET 8. Ваш .NET код працює набагато швидше завдяки новому середовищу виконання на основі Jiterpreter, яке забезпечує часткову підтримку компіляції just-in-time (JIT) для WebAssembly. З новим середовищем виконання компоненти рендеряться на 20% швидше, а десеріалізація JSON відбувається вдвічі швидше!


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


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

Новий шаблон Blazor Web App

Почати роботу з усіма новими функціями Blazor у .NET 8 легко за допомогою нового шаблону проєкту Blazor Web App. Це ваше єдине місце для всіх ваших потреб у веб-розробці.

Шаблон Blazor Web App

Шаблон Blazor Web App містить зручні параметри для:


Тип автентифікації: швидко налаштуйте автентифікацію за допомогою ASP.NET Core Identity з інтерфейсом користувача, повністю реалізованим за допомогою компонентів Blazor.

 Інтерактивний режим візуалізації: виберіть, які інтерактивні режими візуалізації ви хочете ввімкнути: сервер, WebAssembly або обидва з автоматичним.

Інтерактивне розташування: визначте, чи хочете ви, щоб уся ваша програма була інтерактивною, чи лише окремі компоненти та сторінки.

Додайте зразки сторінок: виберіть, щоб включити кілька зразків сторінок, щоб розпочати роботу, або просто почніть із порожнього проєкту.



Параметри шаблону Blazor Web App

Щоб спробувати створити свій перший вебдодаток Blazor Web App за допомогою .NET 8, просто перейдіть на сторінку https://blazor.net і натисніть «Почати» , щоб розпочати навчання Blazor.


Новий Blazor scaffolder (прев’ю)

Ви можете швидко розпочати роботу зі статичним рендерингом сервера Blazor і QuickGrid, щоб відображати дані з бази даних за допомогою нового скаффолдера Blazor, який тепер доступний з останньою версією Visual Studio Preview. Ви можете використовувати Blazor scaffolder, клацнувши правою кнопкою миші на проєкт в Solution Explorer і вибравши Add > New Scaffolded Item, а потім вибравши Razor Components using Entity Framework (CRUD).

Риштувальник Blazor

Скаффолдер Blazor генерує основні сторінки створення, читання, оновлення та видалення (CRUD) на основі моделі даних Entity Framework Core. Ви можете створювати окремі сторінки або всі сторінки CRUD за один раз. Ви вибираєте клас моделі та DbContext, що слід використовувати, за потреби створюючи новий DbContext.

Варіанти будівельних лісів Blazor

Потім до вашого проєкту буде додано створені компоненти Blazor, щоб увімкнути операції CRUD у вибраному класі моделі.

Компоненти Scaffolded Blazor

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


Згенерований компонент Index.razor QuickGrid використовується для відображення даних, тому ви можете легко налаштувати спосіб відображення даних і ввімкнути інтерактивність, щоб скористатися перевагами багатьох його функцій.


Ось приклад того, як виглядають компоненти скаффолдера під час роботи програми:

Скаффолдований інтерфейс користувача Blazor із QuickGrid

Типові атрибути для MVC

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


Наприклад, тепер ви можете вказати тип відповіді для дії контролера API таким чином:

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

Кінцеві точки API ідентифікації

ASP.NET Core тепер надає кінцеві точки API для взаємодії з ASP.NET Core Identity. Ці кінцеві точки забезпечують програмний доступ до функціональних можливостей для реєстрації та входу користувачів, що спрощує налаштування автентифікації для браузера та мобільних клієнтських програм. Кінцеві точки можна використовувати як для аутентифікації на основі файлів cookie, так і для автентифікації на основі маркерів. Перегляньте публікацію в блозі Джеремі Лікнесса про те, що нового в ідентифікації в .NET 8, щоб дізнатися все про те, як налаштувати та використовувати ці нові кінцеві точки.

Покращене прив’язування форм для мінімальних API і проміжного програмного забезпечення для захисту від підробки

ASP.NET Core додає підтримку проміжного програмного забезпечення для захисту від підробки, яке підтримує перевірку маркерів захисту від підробки в запитах у всіх реалізаціях фреймворку (Blazor, мінімальні API, MVC). Крім цього, зв’язування форм у мінімальних API також покращено завдяки підтримці зв’язування складних типів із вхідних даних форми, використовуючи ту саму логіку зв’язування, яку спільно використовує Blazor.

Перепідключення SignalR із збереженням стану

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

Підтримка ключових служб при ін'єкційній залежності

ASP.NET Core тепер підтримує використання ключових служб під час ін’єкції залежностей (іноді їх називають «Keyed DI»). Keyed DI дозволяє мати кілька реалізацій певної служби, які відрізняються за допомогою зручної для розробника назви. Наприклад, ви можете мати підключення до бази даних для профілів користувачів під назвою «UserProfiles» і інше для вмісту кошика під назвою «ShoppingCarts».

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

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

Реєстрація ключових послуг:

 

Сервіси з ключем реєструються в колекції сервісів за допомогою унікальних ключів:

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

Використання ключових служб:

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

Щоб скористатися підтримкою нових ключових служб, додайте цільовий параметр до атрибута [FromKeyedServices(“keyName”)].


Наприклад, ось приклади використання ключових служб у контролерах і мінімальних API:


У контролерах MVC:

У мінімальних API:


Подібним чином у мінімальних налаштуваннях API ін’єкція кількох ключових служб у кінцеві точки спрощена:

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

Метрики

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


ASP.NET Core тепер надає широкі показники часу виконання за допомогою System.Diagnostics.Metrics , нового крос-платформного API, розробленого в тісній співпраці зі спільнотою OpenTelemetry .


Ці нові показники вносять багато покращень порівняно з наявними лічильниками подій:


– Нові види вимірювань за допомогою лічильників, датчиків і гістограм.

– Потужні звіти з багатовимірними значеннями.

– Інтеграція в ширшу нативну хмарну екосистему шляхом узгодження зі стандартами OpenTelemetry.


Ви можете прочитати все про нові показники, доступні в ASP.NET Core, і про те, як їх інтегрувати у ваші системи моніторингу, у документації про показники ASP.NET Core .


Популярним способом використання показників є Grafana, хмарний інструмент візуалізації даних OSS. Команда .NET опублікувала інформаційні панелі Grafana, створені на основі нових показників. Інформаційні панелі дозволяють у режимі реального часу бачити статус ваших програм ASP.NET Core.

Інформаційна панель .NET Grafana

Завантажте інформаційні панелі безпосередньо з .NET team @ grafana.com і дізнайтеся більше на .NET Grafana dashboards .

Транспортування іменованих каналів

ASP.NET Core тепер надає транспорт іменованих каналів для міжпроцесного зв’язку (IPC) у Windows. Іменовані канали добре інтегруються з безпекою Windows для контролю доступу клієнта до каналу. Перегляньте документацію ASP.NET Core про зв’язок між процесами за допомогою gRPC , щоб дізнатися все про налаштування IPC за допомогою іменованих каналів або сокетів домену Unix.

Кешування виводу на основі Redis

ASP.NET Core у .NET 8 додає підтримку використання Redis як розподіленого кешу для кешування вихідних даних. Кешування вихідних даних забезпечує гнучкий спосіб кешування HTTP-відповідей із сервера. Використання Redis для зберігання кешу забезпечує узгодженість між серверними вузлами через спільний кеш, який переживає окремі серверні процеси.

Оснащення маршруту

Маршрутизація запитів є ключовою частиною будь-якої вебпрограми. Нові функції інструментів для маршрутів у Visual Studio роблять роботу з маршрутами ASP.NET Core простішою, ніж будь-коли раніше. Ці функції включають:

– Підсвічування синтаксису маршруту

– Доповнення редактора для відповідності назв параметрів і маршрутів

– Доповнення редактора для обмежень маршруту

– Аналізатори маршрутів і виправлення типових синтаксичних помилок


Наприклад, ось як виглядають маршрути з .NET 7:

Інструменти маршруту .NET 7

А ось як вони виглядають у .NET 8:

Інструменти маршруту .NET 8

Ви можете прочитати все про нові функції інструментів для маршрутів у дописі в блозі Джеймса Ньютона-Кінга ASP.NET Core Route Tooling Enhancements in .NET 8 .

Покращення дебагування

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


Наприклад, ось як виглядає перевірка HttpContext за допомогою .NET 7:

 

Налагодження HttpContext з .NET 7

Ось як це виглядає з .NET 8, де найважливіші значення видно одразу:

Налагодження HttpContext з .NET 8

Ознайомтеся з усіма новими вдосконаленнями налагодження ASP.NET у публікації Джеймса Ньютона-Кінга про вдосконалення налагодження в .NET 8 .


JavaScript SDK і система проєктів

Часто під час роботи з ASP.NET Core вам також потрібно працювати з JavaScript та екосистемою JavaScript. Поєднання світу .NET і JavaScript може бути складним завданням. Новий SDK для JavaScript і система проєктів у Visual Studio спрощують використання .NET із зовнішніми фреймворками JavaScript. JavaScript SDK забезпечує інтеграцію MSBuild для створення, запуску, налагодження, тестування та публікації коду JavaScript або TypeScript разом із кодом .NET. Ви можете легко інтегрувати такі популярні інструменти створення JavaScript, як WebPack, Rollup, Parcel, esbuild та інші.


Ви можете швидко почати використовувати ASP.NET Core з Angular, React і Vue за допомогою наданих шаблонів Visual Studio:

SPA шаблони

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


Ви можете скористатися діалоговим вікном «Install New npm Packages», щоб легко знайти та встановити залежності npm:

Діалогове вікно встановлення нових пакетів npm

Коли ви створюєте свій проєкт JavaScript, JavaScript SDK встановить будь-які залежності пакетів npm. Потім ви можете запустити програму з Visual Studio або в командному рядку за допомогою dotnet run. У Visual Studio ви отримуєте розширену підтримку налагодження коду .NET і JavaScript.


Ви також можете використовувати Visual Studio Test Explorer, щоб виявити та запустити свої тести:

Test Explorer для тестів JavaScript

Ви можете дізнатися більше про спільну роботу з .NET і JavaScript у Visual Studio в документах Visual Studio для JavaScript.

І ще багато іншого!

Це лише приклад того, що нового в ASP.NET Core для .NET 8. Щоб отримати повний список, перегляньте примітки до випуску ASP.NET Core у .NET 8.

Оновити наявний проєкт

Щоб оновити наявну програму ASP.NET Core з .NET 7 до .NET 8, виконайте дії, описані в розділі Перехід з ASP.NET Core 7.0 на 8.0


Щоб оновити наявну програму ASP.NET Core з .NET 8 RC2 до .NET 8, оновіть усі посилання на пакет ASP.NET Core до 8.0.0.. У Blazor Web Apps також слід замінити попередні атрибути режиму візуалізації новою директивою  @rendermode:

Додайте @using static Microsoft.AspNetCore.Components.Web.RenderMode до вашого файлу _Imports.razor

– Замініть @attribute [RenderModeInteractiveServer] на @rendermode InteractiveServer

– Замініть @attribute [RenderModeInteractiveWebAssembly]на @rendermode InteractiveWebAssembly

– Замініть@attribute [RenderModeInteractiveAuto] на @rendermode InteractiveAuto

Це воно! І ви готові користуватися перевагами .NET 8.

Дивіться також повний список критичних змін у ASP.NET Core для .NET 8.


.NET 8 на Azure

.NET 8 уже розгорнуто та готово до використання з усіма вашими улюбленими службами Azure, включаючи службу додатків Azure, функції Azure та статичні веб-програми Azure. Почніть працювати з .NET 8 на Azure вже сьогодні!

Легко створюйте хмарні програми за допомогою .NET Aspire і ASP.NET Core

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

Дякуємо!

Дякуємо всім у спільноті, хто допоміг зробити цей реліз .NET 8 можливим! Цей реліз являє собою кульмінацію багатьох проблем GitHub, запитів, коментарів щодо відгуків про дизайн та оновлень документації, внесених багатьма членами спільноти .NET. Без вас ми б не досягли цього!


Ми сподіваємося, що вам сподобається цей випуск ASP.NET Core у .NET 8. Ми з нетерпінням чекаємо почути про ваш досвід роботи з ним. Надсилайте нам будь-які ваші відгуки щодо цього релізу на GitHub.


Ще раз дякую та щасливого кодування!






Posted on 10. November 2023

.NET 8 Performance Improvements in .NET MAUI

.NET 8 Вдосконалення продуктивності .NET 8 в .NET MAUI

 

Основна увага в .NET MAUI у релізі .NET 8 приділяється якості. Тому ми зосередилися на виправленні помилок замість того, щоб гнатися за високими показниками продуктивності. У .NET 8 ми об'єднали 1 559 запитів, які закрили 596 проблем. Вони включають зміни від команди .NET MAUI, а також від спільноти .NET MAUI. Ми оптимістично налаштовані, що це повинно призвести до значного підвищення якості в .NET 8.

Проте! У нас є ще багато змін у продуктивності, які ми можемо продемонструвати. Спираючись на фундаментальні покращення продуктивності  в .NET 8 ми постійно знаходимо легку здобич, і на GitHub були проблеми з продуктивністю, які ми намагалися вирішити. Наша мета — продовжувати робити .NET MAUI швидшим з кожним релізом, читайте далі, щоб дізнатися подробиці!


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

        .NET 7 Покращення продуктивності в .NET MAUI

        .NET 6 Покращення продуктивності в .NET MAUI


Зміст


Нові функції

-      AndroidStripILAfterAOT

-      AndroidEnableMarshalMethods

-      NativeAOT на iOS


Побудова та продуктивність внутрішнього циклу

-         Відфільтруйте вихідні дані Android ps -A за допомогою grep

-         Перенесення використання vcmeta.dll з WindowsAppSDK на C#

-        Покращення віддалених збірок iOS на Windows

-        Покращення внутрішнього циклу Android

-        Компіляція XAML більше не використовує LoadInSeparateAppDomain


Покращення продуктивності або розміру програми

-        Структури та IEquatable в .NET MAUI

-        Виправлено проблему продуктивності в {AppThemeBinding}

-        Зверніться до CA1307 та CA1309 для отримання інформації про продуктивність

-        Зверніться до CA1311 для отримання інформації

-        Видалення невикористаної події ViewAttachedToWindow на Android

-        Видаліть непотрібні System.Reflection для {Binding}

-        Використовуйте StringComparer.Ordinal для словника та хеш-набору

-        Зменшення взаємодії з Java у MauiDrawable на Android

-        Покращення продуктивності верстки Label на Android

-        Зменшення викликів взаємодії Java для елементів керування в .NET MAUI

-        Покращення продуктивності Entry.MaxLength на Android

-        Зменшення використання пам'яті CollectionView на Windows

-        Використовуйте атрибут UnmanagedCallersOnlyAttribute на платформах Apple

-        Швидша взаємодія з Java для рядків на Android

-        Швидша взаємодія з Java для подій C# на Android

-        Використання функціональних покажчиків для JNI

-        Видалено Xamarin.AndroidX.Legacy.Support.V4

-        Дедуплікація генериків на iOS та macOS

-        Виправлено реалізацію System.Linq.Expressions на iOS-подібних платформах

-        Встановіть DynamicCodeSupport=false для iOS та Catalyst


Витоки пам'яті

-        Витоки пам'яті та якість

-        Діагностика витоків в .NET MAUI

-        Патерни, що призводять до витоків: Події C#

-        Кільцеві посилання на платформах Apple

-        Аналізатор Roslyn для платформ Apple

Інструменти та документація

-        Спрощені dotnet-trace та dotnet-dsrouter

-        Підтримка мобільних пристроїв dotnet-gcdump 


Нові функції

AndroidStripILAfterAOT

Одного разу у нас виникла геніальна думка: якщо AOT попередньо компілює методи C#, то чи потрібен нам керований метод? Видалення тіла методу C# дозволило б зменшити розмір збірок.  Додатки .NET iOS вже роблять це, так чому б не зробити це і для Android?

Хоча ідея проста, реалізація не була такою: iOS використовує "повний" AOT, який перетворює всі методи AOT у форму, що не вимагає використання JIT під час виконання. Це дозволило iOS запустити cil-strip видаляючи всі тіла методів з усіх керованих типів.

На той час Xamarin.Android підтримував лише "звичайний" AOT, а звичайний AOT вимагає JIT для певних конструкцій, таких як узагальнені типи та узагальнені методи. Це означало, що спроба запустити cil-strip призведе до помилок під час виконання, якщо буде видалено тіло методу, яке насправді потрібно під час виконання. Це було особливо погано, оскільки cil-strip могла видалити лише всі тіла методів!

Ми повторно впроваджуємо IL-розбірку для .NET 8. Додаємо нову властивість $(AndroidStripILAfterAOT) для MSBuild. При значенні true завдання <MonoAOTCompiler/> буде відстежувати, які тіла методів були фактично AOT'ені, зберігаючи цю інформацію у %(_MonoAOTCompiledAssemblies.MethodTokenFile), а нове завдання <ILStrip/> буде оновлювати вхідні збірки, видаляючи всі тіла методів, які можна видалити.

 

За замовчуванням увімкнення $(AndroidStripILAfterAOT) замінить стандартне налаштування $(AndroidEnableProfiledAot), дозволяючи вилучити всі обрізані AOT'івські методи. Цей вибір було зроблено тому, що $(AndroidStripILAfterAOT) є найбільш корисним при AOT-компіляції всього вашого додатку. Профільоване вилучення AOT та IL можна використовувати разом, явно встановивши обидва параметри у файлі .csproj, але єдиною перевагою буде невелике зменшення розміру .apk:

.apk для нового додатку dotnet для Android:

Зауважте, що AndroidStripILAfterAOT=false та AndroidEnableProfiledAot=true є типовим середовищем конфігурації релізу, для 7.7MB.

Проєкт, який встановлює лише AndroidStripILAfterAOT=true, неявно встановлює AndroidEnableProfiledAot=false, призводить до отримання програми розміром 8.1 МБ.

Дивіться xamarin-android#8172 та dotnetdotnet/runtime#86722, щоб дізнатися більше про цю можливість.

AndroidEnableMarshalMethods

 

.NET 8 вводить нове експериментальне налаштування для конфігурацій Release:

Ми сподіваємося зробити цю функцію доступною за замовчуванням у .NET 9, але наразі ми надаємо цю можливість як експериментальну. Програми, які орієнтовані лише на одну архітектуру, наприклад RuntimeIdentifier=android-arm64, ймовірно, зможуть увімкнути цю функцію без проблем.

Загальні відомості про методи Маршала

Метод Маршала JNI - це вказівник на функцію, що викликається з JNI, який надається в JNIEnv::RegisterNatives(). Наразі маршальські методи JNI надаються через взаємодію між кодом, який ми генеруємо, та JNINativeWrapper.CreateDelegate():

-        Наш генератор коду видає "справжній" JNI метод, який можна викликати.

-         JNINativeWrapper.CreateDelegate() використовує System.Reflection.Emit для обгортки методу для обробки виключень.

Маршальські методи JNI потрібні для всіх переходів з Java на C#.

 

Розглянемо віртуальний метод Activity.OnCreate():

Activity.n_OnCreate_Landroid_os_Bundle_() - це метод маршала JNI, який відповідає за перетворення параметрів зі значень JNI у типи C#, перенаправлення виклику методу до Activity.OnCreate() та (за необхідності) перетворення значення, що повертається, назад до JNI.

Activity.GetOnCreate_Landroid_os_Bundle_Handler() є частиною інфраструктури реєстрації типів, надаючи екземпляр Delegate до RegisterNativeMembers .RegisterNativeMembers(), який згодом передається до JNIEnv::RegisterNatives().

Хоча це і працює, результат не є неймовірно продуктивним: якщо не використовувати один з оптимізованих типів делегатів, доданих в xamarin-android#6657, System.Reflection.Emit використовується для створення обгортки навколо методу marshal, чого ми намагалися уникати роками.

Отже, ідея: оскільки ми вже збираємо нативний інструментарій і використовуємо LLVM-IR для створення libxamarin-app.so, що, якби ми видали нативні імена методів Java і пропустили все, що було зроблено в рамках Runtime.register() і JNIEnv.RegisterJniNatives()?

 

Дано:

Під час збирання, libxamarin-app.so міститиме цю функцію:

Під час виконання програми, виклик Runtime.register(), присутній в Java викликається Java-обгортці, буде або пропущено, або не буде виконуватися, і Android/JNI натомість перетворить MyActivity.n_onCreate() у Java_crc..._MyActivity_n_1onCreate().

Ми називаємо цю роботу "LLVM Marshal Methods", яка наразі є експериментальною в .NET 8. Багато особливостей все ще досліджуються, і ця функція буде поширюватися на різні області.

Дивіться xamarin-android#7351, щоб дізнатися більше про цю експериментальну функцію.

NativeAOT на iOS

У .NET 7 ми почали експеримент, щоб побачити, що потрібно для підтримки NativeAOT на iOS. Перехід від прототипу до початкової реалізації: .NET 8 Preview 6 включав NativeAOT як експериментальну функцію для iOS.

 

Щоб вибрати NativeAOT у проєкті MAUI iOS, скористайтеся наступними налаштуваннями у файлі проєкту:

 

Потім створити додаток для iOS-пристрою:

Зауваження. Ми можемо розглянути можливість уніфікації та покращення назв властивостей MSBuild для цієї функції у майбутніх релізах .NET. Щоб виконати одноразову збірку у командному рядку, вам також може знадобитися вказати -p:PublishAotUsingRuntimePack=true на додаток до -p:PublishAot=true.

Однією з головних проблем першого релізу було те, як робоче навантаження iOS підтримує інтероперабельність Objective-C. Проблема була пов'язана в основному з системою реєстрації типів, яка є ключовим компонентом для ефективної підтримки iOS-подібних платформ (дивіться  документацію  для  деталей). У своїй реалізації система реєстрації типів залежить від токенів метаданих типів, які недоступні у NativeAOT. Тому, щоб скористатися перевагами високоефективного середовища виконання NativeAOT, нам довелося адаптуватися. dotnetdotnet/runtime#80912 містить обговорення того, як розв'язати цю проблему, і, нарешті, в xamarin-macios#18268 ми реалізували новий керований статичний реєстратор, який працює з NativeAOT. Новий керований статичний реєстратор не тільки сумісний з NativeAOT, але і набагато швидший за стандартний, і доступний для всіх підтримуваних середовищ виконання (див. у  документації for докладніше).

На цьому шляху нам дуже допомогла наша GH-спільнота, і їхній внесок (огляди коду, PR) був дуже важливим, щоб допомогти нам швидко рухатися вперед і випустити цю функцію вчасно. Ось деякі з багатьох PR, які допомогли нам і розблокували наш шлях:

-        dotnet/runtime#77956

-       dotnet/runtime#78280

-        dotnet/runtime#82317

-        dotnet/runtime#85996

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

З появою .NET 8 Preview 6 ми нарешті змогли випустити нашу першу версію NativeAOT на iOS, яка також підтримує MAUI. Дивіться в  пост в блозі про .NET 8 Preview 6, щоб дізнатися більше про те, чого нам вдалося досягти в початковій версії.

У наступних випусках .NET 8 результати значно покращилися, оскільки ми виявляли та вирішували проблеми на цьому шляху. На графіку нижче показано порівняння розміру шаблонних додатків .NET MAUI для iOS у попередніх версіях:

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

-        dotnet/runtime#87924 - виправлено серйозну проблему з розміром NativeAOT з AOT-несумісними шляхами коду у System.Linq.Expressions, а також зроблено повністю сумісними з NativeAOT при націлюванні на iOS

-        xamarin-macios#18332 - зменшено розмір розділу __LINKEDIT Export Info у вилучених двійкових файлах

Крім того, в останньому випуску RC 1 розмір додатків ще більше зменшився, досягнувши  на 50% меншого розміру для шаблонних додатків .NET MAUI для iOS порівняно з Mono. Найвпливовіші проблеми/ПР, які сприяли цьому:

-        xamarin-macios#18734 - Зробити Full  режимом з'єднання за замовчуванням для NativeAOT

-        xamarin-macios#18584 - Зробити обрізку кодової бази сумісним за допомогою серії PR.

Попри те, що розмір програми був основною метрикою, на якій ми зосередилися, для випуску RC 1 ми також виміряли час запуску для шаблонного додатка .NET MAUI для iOS, порівнюючи NativeAOT і Mono, де NativeAOT показав майже вдвічі швидший час запуску.

Основні висновки

Для сценаріїв NativeAOT на iOS зміна режиму зв'язування за замовчуванням на Full (xamarin-macios#18734), ймовірно, є найбільшим покращенням для розміру програми. Але водночас, ця зміна може призвести до поломки додатків, які не є повністю сумісними з AOT та обрізкою. У режимі Full, тример може обрізати несумісні з AOT шляхи коду (згадайте про використання рефлексії), доступ до яких здійснюється динамічно під час виконання. Режим зв'язування Full  не є типовою конфігурацією у разі використання середовища виконання Mono, тому деякі програми можуть бути не повністю сумісними з AOT.

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

-        Як перший крок, ми увімкнули попередження про обрізання, AOT та однофайлові попередження за замовчуванням у xamarin-macios#18571. Увімкнені попередження мають попередити наших клієнтів про те, що використання певного фреймворку, бібліотеки або деяких конструкцій C# у їхньому коді несумісне з NativeAOT - і може призвести до аварійного завершення роботи під час виконання. Ця інформація має допомогти нашим клієнтам писати  код сумісний з AOT, а також допомогти нам покращити наші фреймворки та бібліотеки з тією ж метою — повністю використати переваги компіляції AOT.

-        Другим кроком було усунення всіх попереджень від збірок Microsoft.iOS та System.Private.CoreLib, про які повідомлялося для шаблонного додатку iOS з: xamarin-macios#18629 та dotnetdotnet/runtime#91520.

-        У наступних випусках ми плануємо вирішити проблеми, пов'язані з фреймворком MAUI, та покращити загальний користувацький досвід. Наша мета — створити повністю сумісний з AOT та обрзкою фреймворк.

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

Щоб стежити за подальшим прогресом, див. dotnetdotnet/runtime#80905. І останнє, але не менш важливе, ми хотіли б подякувати нашим учасникам GH, які допомагають нам зробити NativeAOT на iOS можливим.

Побудова та продуктивність внутрішнього циклу

Відфільтруйте вихідні дані Android ps -A за допомогою grep

При перегляді внутрішнього циклу Android для проєкту .NET MAUI з допомогою PerfView ми виявили, що близько 1,2% процесорного часу витрачається лише на отримання ідентифікатора процесу запущеного Android-додатку.

Змінивши багатослівність виводу на Diagnostics -  Tools > Options > Xamarin > Xamarin Diagnostics output , ви зможете побачити:

Розширення Xamarin/.NET MAUI у Visual Studio щосекунди опитує, чи не завершено роботу програми. Це корисно для зміни стану кнопки відтворення/зупинки, якщо ви примусово закриваєте програму тощо.

 

Тестуючи на Pixel 5, ми побачили, що команда насправді виводить 762 рядки!

Натомість ми могли б зробити щось на кшталт:

Де ми передаємо вивід ps -A до команди grep на пристрої Android. Так, Android має підмножину unix-команд! Ми фільтруємо або за рядком, що містить PID, або за назвою пакунка вашої програми.

 

В результаті тепер IDE розбирає лише 4 рядки:

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

Ця можливість з'явилася в останніх версіях Visual Studio 2022, що покращує цей сценарій для всіх користувачів Xamarin і .NET MAUI.

Перенесення використання vcmeta.dll з WindowsAppSDK на C#

 

Ми виявили, що кожна інкрементна збірка проєкту .NET MAUI, що працює під Windows, витрачає час:

Це компілятор XAML для WindowsAppSDK, який компілює XAML для WinUI3 (не .NET MAUI XAML). У проєктах .NET MAUI дуже мало XAML цього типу, фактично, єдиним файлом є файл Platforms/Windows/App.xaml у шаблоні проєкту.

 

Цікаво, що якщо в інсталяторі Visual Studio встановити Desktop development with C++ workload, то цей час просто зникне!

Компілятор XAML WindowsAppSDK звертається до власної бібліотеки з робочого навантаження C++, vcmeta.dll, щоб обчислити хеш для файлів збірки .NET. Це використовується для прискорення інкрементальних збірок — якщо хеш змінюється, компілюйте XAML заново. Якщо vcmeta.dll не було знайдено на диску, компілятор XAML фактично "перекомпілював все" при кожній інкрементальній збірці.

Для початкового виправлення ми просто включили невелику частину навантаження C++ як залежність .NET MAUI у Visual Studio. Дещо більший розмір інсталяції був гарним компромісом для економії до 4 секунд часу інкрементальної збірки.

 

Далі ми реалізували функціонал хешування vcmeta.dll звичайною мовою C# за допомогою System.Reflection.Metadata, щоб обчислювати ідентичні хеш-значення, як і раніше. Ця реалізація була не тільки кращою, оскільки ми могли позбутися залежності від робочого навантаження C++, але й швидшою! Час обчислення одного хешу:

Деякі з причин, чому це було швидше:

-       Не залучені p/invoke або COM-інтерфейси.

-        System.Reflection.Metadata має швидкий API на основі структур, що ідеально підходить для ітерацій над типами в .NET збірці та обчислення хеш-значення.

В результаті CompileXaml може бути навіть швидшим за 9 мс в інкрементних збірках.

 

Цю можливість було включено до WindowsAppSDK 1.3, який тепер використовується .NET MAUI у .NET 8. Докладні відомості про це вдосконалення див. у WindowsAppSDK#3128.

Покращення віддалених збірок iOS на Windows

Порівнюючи продуктивність внутрішнього циклу для iOS, було виявлено значний розрив між "віддаленою iOS" розробкою на Windows і локальною розробкою на macOS. Було зроблено багато невеликих удосконалень, заснованих на порівнянні файлів .binlog внутрішнього циклу, записаних на macOS, з файлами, записаними всередині Visual Studio на Windows.

Деякі приклади включають:

-        maui#12747: не копіювати явно файли на сервер збірки

-        xamarin-macios#16752: не копіювати файли на сервер збірки для операції видалення

-        xamarin-macios#16929: пакетне видалення файлів через DeleteFilesAsync

-        xamarin-macios#17033: кешувати шлях до компілятора AOT

-       Розширення Xamarin/MAUI Visual Studio: під час запуску dotnet-install.sh на віддалених хостах збірки встановіть явний прапорець процесора для комп'ютерів M1 Mac.

Ми також зробили деякі покращення для всіх проектів iOS та MacCatalyst, такі як:

-         xamarin-macios#16416: не обробляйте збірки знову і знову

Покращення внутрішнього циклу Android

Ми також зробили багато невеликих поліпшень у "внутрішній цикл" на Android  —  більшість з них були зосереджені на конкретній області.

Раніше проєкти Xamarin.Forms мали розкіш бути організованими в декілька проєктів, таких як:

-        YourApp.Android.csproj: Проєкт програми Xamarin.Android

-        YourApp.iOS.csproj: Проєкт додатку Xamarin.iOS

-        YourApp.csproj: бібліотека класів netstandard2.0

Де майже вся логіка програми Xamarin.Forms містилася в проекті netstandard2.0. Майже всі інкрементні збірки були б змінами до XAML або C# у бібліотеці класів. Така структура дозволила Xamarin.Android MSBuild-цілям повністю пропустити багато специфічних для Android кроків MSBuild. У .NET MAUI функція "єдиного проекту" означає, що кожна інкрементальна збірка повинна виконувати ці специфічні для Android кроки збірки.

Зосередившись саме на покращенні цієї сфери, ми внесли багато невеликих змін, таких як:

-        java-interop#1061: уникнення string.Format()

-        java-interop#1064: покращено ToJniNameFromAttributesForAndroid

-        java-interop#1065: уникнення перевірки File.Exists()

-        java-interop#1069: виправлено більше місць використання TypeDefinitionCache

-        java-interop#1072: використання меншої кількості System.Linq для користувацьких атрибутів

-        java-interop#1103: використання MemoryMappedFile при використанні Mono.Cecil

-        xamarin-android#7621: уникнення перевірки File.Exists()

-        xamarin-android#7626: покращено роботу LlvmIrGenerator.

-        xamarin-android#7652: швидкий шлях для <CheckClientHandlerType/>

-        xamarin-android#7653: затримка ToJniName під час генерації AndroidManifest.xml

-        xamarin-android#7686: ліниве заповнення пошуку ресурсів

Ці зміни мають покращити інкрементні збірки у всіх типах проектів .NET 8 для Android.

Компіляція XAML більше не використовує LoadInSeparateAppDomain

Переглядаючи звіт JITStats в PerfView (для MSBuild.exe):

Схоже, що Microsoft.Maui.Controls.Build.Tasks.dll проводив багато часу в JIT. Що було незрозуміло, так це те, що це була інкрементна збірка, де все вже повинно бути завантажено. Робота JIT вже повинна бути виконана?

Причиною є використання атрибута [LoadInSeparateAppDomain], визначеного за допомогою <XamlCTask/> у .NET MAUI. Це функція MSBuild, яка дозволяє завданням MSBuild запускатися в ізольованому AppDomain - з очевидним недоліком продуктивності. Однак, ми не могли просто видалити його, оскільки це призвело б до ускладнень...

[LoadInSeparateAppDomain] також зручно скидає весь статичний стан при повторному запуску <XamlCTask/>. Це означає, що майбутні інкрементні збірки потенційно використовуватимуть старі (сміттєві) значення. Існує декілька місць, які кешують об'єкти Mono.Cecil з міркувань продуктивності. Якщо цього не зробити, можуть виникнути дуже дивні помилки.

Для того, щоб зробити цю зміну, ми переробили весь статичний стан у компіляторі XAML, щоб він зберігався у полях та властивостях екземпляра. Це загальне покращення дизайну програмного забезпечення, на додаток до можливості безпечно видалити [LoadInSeparateAppDomain].

 

Результати цієї зміни для інкрементальної збірки на ПК з Windows:

Це дозволило заощадити близько 587 мс на інкрементних збірках на всіх платформах, що становить покращення на 82%. Це ще більше допоможе у великих рішеннях з декількома проєктами .NET MAUI, де <XamlCTask/> виконується декілька разів.

Дивіться maui#11982 для більш детальної інформації про це покращення.

Покращення продуктивності або розміру програми

Структури та IEquatable в .NET MAUI

 

За допомогою профілю Visual Studio .NET Object Allocation Tracking на прикладі клієнтського додатку .NET MAUI ми побачили:


Це здається непомірним обсягом пам'яті для запуску прикладу програми!

 

Заглибимось, щоб побачити, де ці структури були створені:

Основна проблема полягала в тому, що ця структура не реалізовувала IEquatable<T> і використовувалась як ключ для словника. Правило аналізу коду CA1815 було розроблено для виявлення цієї проблеми. Це правило не вмикається за замовчуванням, тому проєкти повинні вибрати його.

Щоб вирішити це:

-        Підписка є внутрішньою для .NET MAUI, і її використання дозволило зробити структуру доступною лише для читання. Це стало просто додатковим покращенням.

·        Ми зробили CA1815 помилкою збірки у всьому репозиторії dotnet/maui.

·        Ми реалізували IEquatable<T> для всіх типів struct.

Після цих змін ми більше не змогли знайти Microsoft.Maui.WeakEventManager+Subscription у знімках пам'яті взагалі. Що дозволило заощадити ~21 МБ розподіленої пам'яті у цьому прикладі програми. Якщо у ваших проєктах використовується struct, то варто зробити CA1815 помилкою збірки.

Меншу цільову версію цієї зміни було перенесено до MAUI у .NET 7. Докладні відомості про це покращення наведено у maui#13232.

Виправлено проблему продуктивності в {AppThemeBinding}

 

Аналізуючи зразок додатка .NET MAUI від клієнта, ми помітили багато часу, який витрачається на {AppThemeBinding} та WeakEventManager під час скролінгу:

У цьому додатку відбувалося наступне:

-        Стандартний шаблон проєкту .NET MAUI має багато {AppThemeBinding} у файлі Styles.xaml за замовчуванням. Це підтримка світлих та темних тем.

-        {AppThemeBinding} підписується на Application.RequestedThemeChanged

-        Отже, кожен перегляд MAUI підписується на цю подію - можливо, кілька разів.

-        Передплатники — це Dictionary<string, List<Subscriber>>, де відбувається пошук за словником, за яким слідує O(N) пошук операцій відписки.

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

Щоб зробити цей сценарій швидким, поки що в .NET 8:

Раніше:

-        Для будь-якого {AppThemeBinding} він викликає обидва:

-        RequestedThemeChanged -= OnRequestedThemeChanged O(N) times

-       RequestedThemeChanged += OnRequestedThemeChanged постійний час

-       Де -= помітно повільніше, через, можливо, сотні підписників.

Після:

-        Створіть булеву функцію _attached, щоб ми знали "стан", чи вона приєднана, чи ні.

-        Нові прив'язки викликають лише +=, тоді як -= тепер викликатиметься {AppThemeBinding} лише у рідкісних випадках.

-        Більшість програм .NET MAUI не "скасовують" прив'язки, але -= буде використано лише у цьому випадку.

Повну інформацію про це виправлення див. в maui#14625. Див. dotnetdotnet/runtime#61517 про те, як ми можемо реалізувати "слабкі події" у .NET у майбутньому.

Зверніться до CA1307 та CA1309 для отримання інформації про продуктивність

 

Переглядаючи зразок додатка .NET MAUI від клієнта, ми помітили час, що витрачається на "культурно-орієнтовані" операції з рядками:

Цю ситуацію можна покращити, просто викликавши натомість ToLowerInvariant(). У деяких випадках ви можете навіть розглянути можливість використання string.Equals() з StringComparer.Ordinal. У цьому випадку наш код було додатково переглянуто та оптимізовано у статтях Зменшення  Java  взаємодії з  у  MauiDrawable  на  Android.

У .NET 7 ми додали правила аналізу коду CA1307 і CA1309 для виявлення подібних випадків, але, схоже, ми пропустили деякі з них у Microsoft.Maui.Graphics.dll. Ці правила можуть бути корисними для використання у ваших власних додатках .NET MAUI, оскільки уникнення всіх культурно-залежних операцій з рядками може мати значний вплив на мобільні пристрої.

Дивіться maui#14627, щоб дізнатися більше про це покращення.

Зверніться до CA1311 для отримання інформації

Після розгляду правил аналізу коду CA1307 і CA1309 ми пішли далі і розглянули CA1311.

 

Як згадувалося в турецькому  прикладі, подібні дії:

Можуть спричинити неочікувану поведінку в турецьких регістрах, оскільки в турецькій мові символ I (Юнікод 0049) вважається верхнім регістром іншого символу ý (Юнікод 0131), а i (Юнікод 0069) вважається нижнім регістром ще одного символу Ý (Юнікод 0130).

ToLowerInvariant() і ToUpperInvariant() також краще для продуктивності, оскільки інваріантна операція ToLower / ToUpper працює трохи швидше. Це також дозволяє уникнути завантаження поточної культури, що покращує продуктивність запуску.

 

Існують випадки, коли вам потрібно використовувати поточну культуру, наприклад, у випадку типу CaseConverter у .NET MAUI. Для цього вам просто потрібно чітко вказати, яку культуру ви хочете використовувати:

Мета цього CaseConverter - показати користувачеві текст у верхньому або нижньому регістрі. Тому має сенс використовувати для цього CurrentCulture.

Дивіться maui#14773, щоб дізнатися більше про це покращення.

Видалення невикористаної події ViewAttachedToWindow на Android

 

Кожен Label в .NET MAUI був підписаний:

Це залишилося після рефакторингу, але з'явилося у виводі дотнет-траси як:

Де перше — це підписка, а друге — подія, що викликається з Java на C# - тільки для запуску порожнього керованого методу.

 

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

Дивіться maui#14833, щоб дізнатися більше про це покращення.

Видаліть непотрібні System.Reflection для {Binding}

 

Всі прив'язки в .NET MAUI зазвичай потрапляють до шляху коду:

Де ~53% часу, витраченого на застосування прив'язки, з'явилося в dotnet-трасі в методі MethodInfo.GetParameters():

 

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

Ми могли побачити результати цієї зміни в бенчмарку BenchmarkDotNet:

Де ++ позначає нові зміни.

Дивіться maui#14830 для більш детальної інформації про це покращення.

Використання StringComparer.Ordinal для словника та хеш-набору

 

Проаналізувавши зразок додатку .NET MAUI від клієнта, ми помітили, що 4% часу під час прокрутки витрачається на пошук у словнику:

Спостерігаючи за стеком викликів, деякі з них надходили з культурно-орієнтованого пошуку рядків у .NET MAUI:

      



  - microsoft.maui!Microsoft.Maui.PropertyMapper.GetProperty(string)

  -microsoft.maui!Microsoft.Maui.WeakEventManager.AddEventHandler(System.EventHandler<TEventArgs_REF>,string)

- microsoft.maui!Microsoft.Maui.CommandMapper.GetCommand(string)

Які відображаються в dotnet-trace у вигляді суміші рядкових порівнянь:

У випадку Dictionary<string, TValue> або HashSet<string> ми можемо використовувати StringComparer.Ordinal у багатьох випадках, щоб пришвидшити пошук у словнику. Це має дещо покращити продуктивність обробників та всіх елементів управління .NET MAUI на всіх платформах.

Дивіться maui#14900, щоб дізнатися більше про це покращення.

Зменшення взаємодії з Java у MauiDrawable на Android

 

Профілюючи зразок .NET MAUI клієнта під час скролінгу на Pixel 5, ми побачили, як цікаво він проводив час:

У цьому прикладі <Border/> знаходиться всередині <CollectionView/>, тому ви можете бачити, як це відбувається під час прокрутки.

 

Зокрема, ми розглянули код в .NET MAUI, такий як:

Це п'ять викликів з C# на Java. Створення нового методу в PlatformInterop.java дозволило нам скоротити його до одного разу.

 

Ми також покращили наступний метод, який виконує багато викликів з C# на Java:

Щоб бути більш лаконічно реалізованим на Java як:

 

Що зводить нашу нову реалізацію на стороні C# до одного виклику Java та створення структури Android.Graphics.Color:

Після цих змін ми побачили такий вивід dotnet-trace:

Це збільшує продуктивність будь-якого <Border/> (та інших фігур) на Android і зменшує використання процесора на ~1% під час прокрутки у цьому прикладі.

Дивіться maui#14933 для більш детальної інформації про це покращення.

Покращення продуктивності верстки Label на Android

 

Тестуючи різні зразки додатків .NET MAUI на Android, ми помітили, що близько 5,1% часу витрачається на PrepareForTextViewArrange():

 

Більшість часу витрачається на виклик Android.Views.View.Context, щоб потім мати змогу викликати метод розширення:

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

У .NET 7 ми зробили перевантаження для ToPixels(), що дозволяє отримати те саме значення за допомогою Android.Views.View

 

Тож замість цього ми можемо зробити так:

Ця зміна не тільки покращила результати dotnet-trace, але й помітно вплинула на наші LOLs  в  секунду у нашому тестовому додатку порівняно з минулим роком:

Дивіться maui#14980, щоб дізнатися більше про це покращення.

Зменшення викликів взаємодії Java для елементів керування в .NET MAUI

Огляд чудового прикладу .NET MAUI "Surfing App" від @jsuarezruiz:

 

Ми помітили, що багато часу витрачається на взаємодію з Java під час прокрутки:

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

 

Так, наприклад, раніше DispatchDraw() перевизначався у C#, щоб реалізувати поведінку відсікання:

 

Створивши PlatformContentViewGroup.java, ми можемо зробити щось на зразок

setHasClip() викликається, коли відсікання увімкнено/вимкнено у будь-якому елементі управління .NET MAUI. Це дозволило загальному шляху взагалі не взаємодіяти з C#, а лише з тими елементами управління, які ввімкнули відсікання. Це дуже добре, тому що dispatchDraw() викликається досить часто під час верстки Android, скролінгу тощо.

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

 

Для тестування впливу цих змін ми використовували Google's FrameMetricsAggregator від Google який можна налаштувати в Platforms/Android/MainActivity.cs будь-якого додатка .NET MAUI:

API FrameMetricsAggregator є дещо дивним, але дані, які ми отримуємо, є досить корисними. Результатом є таблиця пошуку, де ключ — це тривалість в мілісекундах, а значення — кількість "кадрів", які зайняли цю тривалість. Ідея полягає в тому, що будь-який кадр, який триває довше 16 мс, вважається "повільним" або "смиканим", як іноді кажуть в документації до Android.

 

Приклад .NET MAUI "Surfing App", що працює на Pixel 5:

 

Після внесення змін до ContentViewGroup та WrapperView ми отримали дуже гарне покращення! Навіть у додатку, що інтенсивно використовує обрізки та тіні:

Перегляньте maui#14275 для більш детальної інформації про ці зміни.

Збільшення продуктивності Entry.MaxLength на Android

Досліджуємо зразок клієнта .NET MAUI:

-        Навігація з випадаючого вікна Shell.

-        На нову сторінку з кількома елементами керування введенням.

-        Була помітна затримка у виконанні.

 

Під час профілювання на Pixel 5 одним з “гарячих шляхів” був Entry.MaxLength:

-        Виклики EditTextExtensions.UpdateMaxLength()

-        Getter та setter EditText.Text

-        Виклики EditTextExtensions.SetLengthFilter()

-        EditText.Get/SetFilters()

В результаті ми пересилаємо рядки та IInputFilter[] між C# та Java для кожного елемента управління Entry. Всі елементи управління Entry проходять через цей шлях коду (навіть ті, що мають значення MaxLength за замовчуванням), тому є сенс перенести частину цього коду з C# на Java.

 

Наш код на C# раніше:

Натомість перейшли на Java (з ідентичною поведінкою):

Це дозволяє уникнути маршування (копіювання!) значень рядків і масивів з C# на Java і навпаки. Завдяки цим змінам виклики EditTextExtensions.UpdateMaxLength() стали настільки швидкими, що вони повністю відсутні у виводі dotnet-trace, заощаджуючи ~19 мс при переході на сторінку у клієнтському прикладі.

Дивіться maui#15614, щоб дізнатися більше про це покращення.

Зменшення використання пам'яті CollectionView на Windows

 

Ми розглянули зразок клієнта .NET MAUI з CollectionView на 150 000 прив'язаних до даних рядків. Налагоджуючи те, що відбувається під час виконання, .NET MAUI ефективно виконував:

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

Це був не найкращий підхід, але для покращення ситуації:

-        використовуйте натомість  Dictionary<int, T>, просто дозвольте йому динамічно змінювати розмір.

-        використовуйте TryGetValue(..., out var context), щоб кожен виклик звертався до індексатора на один раз менше, ніж раніше.

-        використовуйте або розмір пов'язаної колекції, або 64 (залежно від того, що менше) як приблизну оцінку того, скільки зображень може поміститися на екрані за один раз

 

Наш код змінюється на:

Після внесення цих змін, знімок пам'яті програми після запуску наступний:

Що економить близько 1 МБ пам'яті при запуску. У цьому випадку краще просто дозволити Словнику самому визначати свій розмір з оцінкою того, якою буде його ємність.

Дивіться maui#16838, щоб дізнатися більше про це покращення.

Використовуйте UnmanagedCallersOnlyAttribute на платформах Apple

Коли некерований код викликає керований код, наприклад, виклик зворотного виклику з Objective-C, раніше в Xamarin.iOS, Xamarin.Mac і .NET 6+ для цієї мети використовувався атрибут [MonoPInvokeCallbackAttribute]. Атрибут [UnmanagedCallersOnlyAttribute] з'явився як сучасна заміна цієї функції Mono, яка реалізована з урахуванням продуктивності.

На жаль, є кілька обмежень при використанні цього нового атрибуту:

·        Метод повинен бути позначений як статичний.

·        Не можна викликати з керованого коду.

·        Повинні бути тільки аргументи, що розбиваються на частини.

·        Не повинен мати параметрів узагальненого типу або міститися в узагальненому класі.

Нам довелося не тільки рефакторити "генератор коду", який створює багато прив'язок для API Apple для AppKit, UIKit і т.д., але й багато ручних прив'язок, які потребували б такої ж обробки.

В результаті більшість функцій зворотного виклику з Objective-C на C# повинні працювати швидше в .NET 8, ніж раніше. Дивіться xamarin-macios#10470 та xamarin-macios#15783 для отримання детальної інформації про ці покращення.

Швидша взаємодія з Java для рядків на Android

При зв'язуванні членів, що мають типи параметрів або типів повернення java.lang.CharSequence, член "перевантажується" для заміни CharSequence на System.String, а "оригінальний" член має суфікс Formatted.

 

Наприклад, розглянемо android.widget.TextView який має функцію getText() та setText() методи, які мають типи параметрів та повертають типи java.lang.CharSequence:

У зв'язаному вигляді це призводить до двох властивостей:

 

"Неформатоване перевантаження" працює шляхом створення тимчасового об'єкта String для виклику форматованого перевантаження, ось так виглядає фактична реалізація:

TextView.Text набагато легше зрозуміти і простіше використовувати для .NET розробників, ніж TextView.TextFormatted.

Проблемою такого підходу є продуктивність: створення нового екземпляру Java.Lang.String вимагає:

1.         Створення керованого однорангового об'єкту (екземпляру Java.Lang.String),

2.         Створення нативного однорангового екземпляру (екземпляр java.lang.String),

3.        І реєстрація співвідношення між (1) і (2)

А потім одразу цим і користуйтесь ..

 

Це особливо помітно у додатках .NET MAUI. Розглянемо приклад клієнта, який використовує XAML для встановлення прив'язаних до даних значень Text  у CollectionView, які зрештою потрапляють до TextView.Text. Профілювання показує:

6.3% часу скролінгу витрачається на встановлення властивості TextView.Text!

 

Цей випадок можна частково оптимізувати: якщо член *Formatted є (1) властивістю і (2) не є віртуальним, то ми можемо безпосередньо викликати метод встановлювача Java.Це дозволяє уникнути необхідності створення керованого однорангового пристрою та реєстрації зв'язку між одноранговими пристроями:

В результаті чого:

Час виклику встановлювача властивості TextView.Text зменшено до 20% від попереднього середнього часу виклику.

Зауважте, що віртуальний випадок є проблематичним з інших причин, але, на щастя, TextView.setText() не є віртуальним і, ймовірно, є одним з найбільш поширених API Android.

Дивіться java-interop#1101 для більш детальної інформації про це покращення.

Швидша взаємодія з Java для подій C# на Android

 

Проаналізувавши вибірку клієнтів .NET MAUI під час прокрутки на Pixel 5, ми побачили ~2,2% часу, витраченого на конструктор IOnFocusChangeListenerImplementor, через підписку на подію View.FocusChange:

MAUI підписується на Android.Views.View.FocusChange для кожного подання, розміщеного на екрані, що відбувається під час прокрутки у цьому прикладі.

 

Переглядаючи згенерований код конструктора IOnFocusChangeListenerImplementor, ми бачимо, що він все ще використовує застарілі API JNIEnv:

Які ми можемо змінити, щоб використовувати новіші/швидші API Java.Interop:

Вони кращі, оскільки еквівалентний виклик JNIEnv.FindClass() кешується, серед іншого. Це був лише один з випадків, який ми випадково пропустили, коли впроваджували нові API Java.Interop в Xamarin. Нам просто потрібно було оновити наш генератор коду, щоб він видавав кращу прив'язку C# для цього випадку.

 

Після цих змін ми побачили натомість результати в dotnet-trace:

Це повинно покращити продуктивність усіх подій C#, які обгортають слухачів Java, шаблон дизайну, який зазвичай використовується у програмах на Java та Android. Сюди входить подія FocusedChanged, яка використовується всіма представленнями .NET MAUI на Android.

 

Дивіться java-interop#1105 для більш детальної інформації про це покращення.

Використання функціональних покажчиків для JNI

 

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

 

Метод C# з назвою CallObjectMethod відповідає за виклик власного інтерфейсу Java (JNI), який викликає JVM для виклику методу Java:

 

У Xamarin.Android, .NET 6 та .NET 7 всі виклики на Java проходять через java_interop_jnienv_call_object_method_a p/invoke, сигнатура якого має такий вигляд:

Що реалізовано на мові C наступним чином:

C# 9 вводить функції вказівники  що дозволило нам дещо спростити роботу — і, як наслідок, пришвидшити її.

Отже, замість того, щоб використовувати p/invoke у .NET 8, ми могли б викликати новий небезпечний метод з назвою CallObjectMethodA:

Який викликає покажчик на функцію C# напряму:

Цей покажчик на функцію оголошено з використанням нового синтаксису, введеного в C# 9:

Порівняння двох реалізацій з ручним бенчмарком:

У Release-збірці середній час виклику JIFunctionPointersTiming займає 97% від часу JIPinvokeTiming, тобто виходить на 3% швидше. Крім того, використання вказівників на функції C# 9 означає, що ми можемо позбутися всіх функцій C java_interop_jnienv_*(), що зменшує libmonodroid.so на ~55 КБ для кожної архітектури.

Дивіться xamarin-android#8234 та java-interop#938 для більш детальної інформації про це покращення.

Видалено Xamarin.AndroidX.Legacy.Support.V4

 

Переглядаючи залежності .NET MAUI для Android, ми помітили підозрілий пакет:

Якщо ви знайомі з Бібліотеками Підтримки Android, це набір пакунків, які Google надає для "переливання" API у попередні версії Android. Це дає їм можливість додавати нові API до старих версій ОС, оскільки екосистема Android (OEM-виробники тощо) оновлюється набагато повільніше, ніж, наприклад, iOS. Цей конкретний пакет, Legacy.Support.V4, насправді підтримує Android аж до Android API 4! Мінімальна підтримувана версія Android в .NET - це Android API 21, яка була випущена в 2017 році.

Виявляється, ця залежність була перенесена з Xamarin.Forms і насправді не була потрібна. Як і очікувалося, ця зміна призвела до того, що з додатків .NET MAUI було видалено багато Java-коду. Настільки багато, що додатки .NET 8 MAUI тепер підпадають під ліміт мультидексів - весь байт-код Dalvik може зафіксувати в одному файлі classes.dex.

 

Детальна розбивка змін розміру за допомогою apkdiff:

Дивіться dotnetdotnet/maui#12232, щоб дізнатися більше про це покращення.

Дедуплікація генериків на iOS та macOS

У .NET 7 додатки для iOS збільшилися у розмірі через використання узагальнень C# у декількох збірках .NET. Коли моно AOT-компілятор .NET 7 зустрічає узагальнений екземпляр, який не обробляється спільним використанням, він видає код цього екземпляра. Якщо той самий екземпляр зустрічається під час AOT-компіляції у декількох збірках, код буде видано кілька разів, що збільшить розмір коду.

У .NET 8 нові опції командного рядка dedup-skip і dedup-include передаються компілятору Mono AOT. Створено нову збірку aot-instances.dll для спільного використання цієї інформації в одному місці у всій програмі.

Зміна була протестована в додатку MySingleView і тестах Monotouch в кодовій базі xamarin/xamarin-macios:

Дивіться xamarin-macios#17766 для більш детальної інформації про це покращення.

Виправлено реалізацію System.Linq.Expressions на iOS-подібних платформах

У .NET 7 кодові шляхи в System.Linq.Expressions контролювалися різними прапорцями, такими як:

-        CanCompileToil

-        CanEmitObjectArrayDelegate

-       CanCreateArbitraryDelegates

 

Ці прапорці керують кодовими шляхами, які є "дружніми до AOT", а які ні. Для десктопних платформ NativeAOT визначає наступну конфігурацію для AOT-сумісного коду:

Що стосується iOS-подібних платформ, то бібліотека System.Linq.Expressions була зібрана з увімкненим константним розмноженням та вилученими керуючими змінними. Це призвело до того, що перелічені вище перемикачі функцій NativeAOT не мали жодного ефекту (не обрізалися під час збирання програми), що потенційно могло призвести до того, що компіляція AOT йшла непідтримуваними шляхами коду на цих платформах.

У .NET 8 ми уніфікували збірку System.Linq.Expressions.dll, щоб забезпечити однакову збірку для всіх підтримуваних платформ і середовищ виконання, а також спростили ці перемикачі для врахування IsDynamicCodeSupported, щоб тример .NET міг видаляти відповідні IL в System.Linq.Expressions.dll під час збірки додатку.

Дивіться dotnetdotnet/runtime#87924 та dotnetdotnet/runtime#89308 для отримання детальної інформації про це покращення.

Встановіть DynamicCodeSupport=false для iOS та Catalyst

У .NET 8 перемикач функцій $(DynamicCodeSupport) встановлено у значення false для платформ:

-        Де неможливо публікувати без компілятора AOT.

-        Коли перекладач не ввімкнений.

Це стосується додатків, що працюють на iOS, tvOS, MacCatalyst тощо.

DynamicCodeSupport=false дозволяє тримеру .NET видаляти шляхи коду в залежності від RuntimeFeature.IsDynamicCodeSupported, наприклад цей  приклад  у  System.Linq.Expressions.

 

Орієнтовна економія становить:

У поєднанні з System.Linq.Expressions  на  iOS-подібних  платформах це дало гарне загальне покращення розміру програми:

Дивіться xamarin-macios#18555 для більш детальної інформації про це покращення.

Витоки пам'яті

Витоки пам'яті та якість

Враховуючи, що основною темою .NET MAUI в .NET 8 є якість, проблеми, пов'язані з пам'яттю, стали основною темою цього випуску. Деякі з виявлених проблем існували навіть у кодовій базі Xamarin.Forms, тому ми раді працювати над створенням фреймворку, на який розробники можуть покластися при створенні крос-платформних .NET додатків.

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

-        Запити

-        Проблеми

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

Якщо порівняти .NET 7 MAUI з .NET 8 MAUI у прикладі додатку, що працює на Windows, виводячи результати виконання GC.GetTotalMemory() на екран:

Порівняння на Windows: .NET 7 проти .NET 8, зображення

Потім порівняйте приклад програми, що працює на macOS, але з набагато більшою кількістю сторінок у стеку навігації:

Порівняння на Mac: .NET 7 проти .NET 8, зображення

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

Діагностика витоків в .NET MAUI

Симптомом витоку пам'яті в .NET MAUI додатку може бути щось на кшталт цього:

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

-        Поверніться.

-        Знову перейдіть на підсторінку.

-        Повторіть.

-        Пам'ять постійно зростає, поки операційна система не закриє програму через нестачу пам'яті.

 

У випадку Android ви можете побачити такі повідомлення журналу, як

У цьому прикладі маса розміром 116 МБ є досить великою для мобільного додатку, а також понад 46 000 об'єктів обгортки C# <-> Java!

Щоб точно визначити, чи підсторінка втрачає, ми можемо зробити кілька модифікацій у додатку .NET MAUI:

 

1.         Додати реєстрацію у фіналізаторі. Наприклад:

Під час навігації по вашому додатку ви можете виявити, що цілі сторінки живуть вічно, якщо повідомлення журналу ніколи не відображається. Це поширений симптом витоку, оскільки будь-яке подання містить .Parent.Parent.Parent і т.д. аж до об'єкта Page.

 

2.      Викликати GC.Collect() десь у додатку, наприклад, у конструкторі підсторінки:

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

Зауважте, що GC.Collect() призначено лише для налагодження. Після завершення дослідження вам не знадобиться ця функція у вашому додатку, тому обов'язково видаліть її після завершення.

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

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

Якщо ви працюєте під Windows, ви також можете скористатися Debug > Windows > Diagnostic Tools у Visual Studio для створення знімків пам'яті у Visual Studio. У майбутньому ми хотіли б, щоб засоби діагностики Visual Studio підтримували програми .NET MAUI, що працюють на інших платформах.

Дивіться нашу вікі-сторінку про пам'яті витоки  wiki, для отримання додаткової інформації про витоки пам'яті у додатках .NET MAUI.

Патерни, що призводять до витоків: Події C#

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

 

Візьмемо, наприклад, кросплатформну властивість Grid.ColumnDefinitions:

-       Grid має сильне відношення на колекцію ColumnDefinitionCollection через BindableProperty.

-    ColumnDefinitionCollection має сильне відношення на Grid через подію ItemSizeChanged.

Якщо ви поставите точку зупинки на рядку з ItemSizeChanged +=, ви побачите, що подія має об'єкт EventHandler, де Target є сильним посиланням назад на Grid.

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

Проблема виникає з часом життя об'єктів: що станеться, якщо ColumnDefinitionCollection існуватиме протягом усього життя програми?

 

Розглянемо наступний Style у Application.Resources або Resources/Styles/Styles.xaml:

Якщо ви застосували цей стиль до сітки на довільній сторінці:

- Основний словник ресурсів програми містить стиль.

-  Стиль містить ColumnDefinitionCollection.

-  ColumnDefinitionCollection містить сітку.

-  На жаль, Grid утримує сторінку через .Parent.Parent.Parent і т.д.

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

Зауваження Проблему з Grid виправлено у maui#16145, але вона є чудовим прикладом ілюстрації того, як події C# можуть піти не так, як треба.

Кільцеві посилання на платформах Apple

Ще з перших днів існування Xamarin.iOS існувала проблема з "циклічними посиланнями", навіть у середовищі виконання, що збирає сміття, як .NET. Об'єкти C# співіснують зі світом посилань на платформах Apple, і тому об'єкт C#, який має підкласи NSObject, може потрапити в ситуацію, коли він випадково може жити вічно — витік пам'яті. Це не є специфічною проблемою .NET, оскільки ви можете так само легко створити таку ж ситуацію в Objective-C або Swift. Зверніть увагу, що цього не відбувається на платформах Android або Windows.

 

Візьмемо, наприклад, наступне кільцеве посилання:

У цьому випадку:

-  parent -> view через Subviews

-  view -> parent через властивість Parent

-  Кількість посилань на обидва об'єкти відмінна від нуля.

- Обидва об'єкти живуть вічно.

 

Ця проблема не обмежується полем або властивістю, ви можете створювати подібні ситуації з подіями C#:

У цьому випадку:

-  MyView -> UIDatePicker через Subviews

- UIDatePicker -> MyView через ValueChanged та EventHandler.Target

- Обидва об'єкти живуть вічно.

Рішення для цього прикладу — зробити метод OnValueChanged static, що призведе до значення null Target в екземплярі EventHandler.

 

Іншим рішенням може бути розміщення OnValueChanged у підкласі, який не є NSObject:

Це шаблон, який ми використовуємо у більшості обробників .NET MAUI та інших підкласах UIView.

Подивіться на MemoryLeaksOniOS якщо ви хочете ізольовано погратися з деякими з цих сценаріїв у додатку для iOS без .NET MAUI.

Аналізатор Roslyn для платформ Apple

 

Також у нас є експериментальний  аналізатор Roslyn, який може виявляти такі ситуації під час збірки. Щоб додати його до проєктів net7.0-ios, net8.0-ios тощо, ви можете просто встановити пакет NuGet:

Деякі приклади попередження можуть бути наступними:

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

Інструменти та документація

Спрощені dotnet-trace та dotnet-dsrouter

У .NET 7 профілювання мобільних додатків було дещо складним завданням. Вам потрібно було запустити dotnet-dsrouter і dotnet-trace разом і виконати всі налаштування правильно, щоб мати змогу отримати .nettrace або speedscope для дослідження продуктивності. Також не було вбудованої підтримки dotnet-gcdump для підключення до dotnet-dsrouter для отримання знімків пам'яті запущеної програми .NET MAUI.

У .NET 8 ми спростили цей сценарій, створивши нові команди для dotnet-dsrouter, які спрощують робочий процес.

 

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

Переконайтеся, що у вас встановлені версії цих інструментів не нижче 8.x:

 

Щоб профілювати Android-додаток на емуляторі Android, спочатку створіть і встановіть свій додаток у режимі Release, наприклад, так:

Далі відкрийте термінал для запуску dotnet-dsrouter

 

Потім у другому вікні терміналу ми можемо встановити системну властивість debug.mono.profile Android, як замінник $DOTNET_DiagnosticPorts:

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

Після запуску програми для Android вона повинна мати можливість підключитися до dotnet-dsrouter -> dotnet-trace і записати інформацію про профілювання продуктивності для дослідження. Аргумент --format є необов'язковим і за замовчуванням має значення .nettrace. Однак файли .nettrace можна переглянути лише за допомогою Perfview у Windows, тоді як JSON-файли speedscope можна переглянути "на" macOS або Linux, завантаживши їх на https://speedscope.app.

Зауваження Якщо ви надаєте ідентифікатор процесу програмі dotnet-trace, вона знає, як визначити, чи є ідентифікатор процесу dotnet-dsrouter, і з'єднатися через нього належним чином.

dotnet-dsrouter має наступні нові команди для спрощення робочого процесу:

-  dotnet-dsrouter android: Пристрої Android

- dotnet-dsrouter android-emu: Емулятори Android

- dotnet-dsrouter ios: пристрої iOS

- dotnet-dsrouter ios-sim: симулятори iOS

Дивіться вікі .NET MAUI для отримання додаткової інформації про профілювання додатків .NET MAUI на кожній платформі.

Підтримка мобільних пристроїв dotnet-gcdump 

У .NET 7 у нас був дещо складний метод (див.  вікі) для отримання знімка пам'яті програми у середовищі виконання Mono (наприклад, iOS або Android). Вам потрібно було використовувати спеціальний для Mono провайдер подій, наприклад:

А потім ми поклалися на Філіпа Навару (Filip Navara) та його інструмент  mono-gcdump (дякуємо Філіпу!), щоб перетворити файл .nettrace у .gcdump, який можна відкрити у Visual Studio або PerfView.

 

У .NET 8 ми тепер маємо dotnet-gcdump для мобільних сценаріїв. Якщо ви хочете отримати знімок пам'яті запущеної програми, ви можете використовувати dotnet-gcdump так само як і dotnet-trace:

Зауваження Для цього потрібні такі самі налаштування, як і для dotnet-trace, наприклад, -p:AndroidEnableProfiler=true, dotnet-dsrouter, команди adb тощо.

 

Це значно спрощує наш робочий процес дослідження витоків пам'яті в додатках .NET MAUI. Дивіться нашу  wiki вікі-сторінку про витоки пам'яті    для отримання додаткової інформації.

 

Source






Posted on 18. October 2023

Announcing .NET MAUI in .NET 8 Release Candidate 2: More Quality

Анонс .NET MAUI у .NET 8 Release Candidate 2: Більше Якості


Сьогодні ми робимо ще один крок на зустріч до загального доступу до .NET 8 (GA), надаючи .NET MAUI у версії 2 (RC2) .NET 8. Як і RC1, на цей випуск поширюється ліцензія на запуск, тому ви можете отримати підтримку під час використання його у своїх робочих програмах. У цьому релізі ми зосередилися на проблемах, які регресували під час попереднього перегляду, і відновили деяку продуктивність, яку було втрачено, коли ми покращили надійність гарячого перезавантаження, візуального менеджера стану, прив’язки та тем додатків.

Покращення якості

 

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


Основні моменти з цього релізу:


Покращення продуктивності: було зроблено кілька покращень продуктивності, зокрема покращено продуктивність ActivityExtensions.GetWindowFrame на Android і продуктивність «Setter Specificity». Ці оптимізації сприяють плавній роботі програми. (#17241 , #17364 , #17230 , #17505 , #17545).

 

 

Виправлення інтерфейсу користувача та елементів керування: було внесено кілька виправлень і оновлень до елементів керування та елементів інтерфейсу користувача, зокрема виправлення, пов’язані з CollectionView, видимістю TabBar, межами RoundRectangle і вирівнюванням тексту Android. Завдяки цьому інтерфейс вашого додатка є більш узгодженим і візуально точнішим на різних платформах. (#16870 , #17240 , #17261 , #17353 , #17430 , #17594, #17567).

 

Спеціалізовані виправлення для платформ: було внесено кілька специфічних  виправлень для платформ, зокрема функцію перетягування, зовнішній вигляд панелі вкладок і певну поведінку платформи, що забезпечує узгоджену взаємодію користувачів на різних платформах. (#15748 , #16561 , #17495 , #17041 , #17358).


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

Додаткова інформація:


- Примітки до релізу .NET MAUI

- .NET для Android

 

- .NET для iOS і Mac

 

Бонус: Реліз Сервісу .NET 7

Сьогодні ми також надіслали 8 реліз  сервісу .NET MAUI (версія 7.0.96) для .NET 7, включаючи вибрані високопріоритетні виправлення макета, витоків пам’яті, CollectionView, безпечної зони тощо. Ви можете скористатися цією версією служби, інсталювавши .NET 8 RC2 одним із наведених нижче методів і продовживши створювати свої програми для .NET 7.


Крім того, ви можете отримати 7.0.96, оновившись до Visual Studio 17.7.5.

Бонус 2: Xcode 15 та Android API 34

 

Тепер розробники Xamarin можуть використовувати Xcode 15 для націлювання на останні версії (наприклад, iOS 17, iPadOS 17) і націлювати Android API 34 , щоб відповідати політикам магазину. Для цього встановіть Visual Studio 17.8 Preview 3 або останню стабільну версію Visual Studio для Mac і налаштуйте середовище, як зазвичай. Це не надає нових API для платформи, але дозволяє продовжувати створення наявних проєктів, поки ви завершите оновлення до .NET 8 і .NET MAUI, незалежно від дати завершення підтримки Xamarin наступного року .

Як оновити

На всіх платформах ви можете розробляти з .NET MAUI за допомогою Visual Studio Code. Установіть розширення .NET MAUI і повідомте нам, як ми можемо покращити це прев’ю для вас у майбутньому.


Завантажте програму встановлення .NET 8 RC2 , а потім інсталюйте .NET MAUI з командного рядка:

 

dotnet workload install maui

 

Після припинення використання Visual Studio для Mac наступного року ви зможете продовжувати розробку за допомогою Visual Studio для Mac після ввімкнення функції попереднього перегляду для .NET 8 у параметрах.

 

Зворотний зв'язок

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


Дякуємо всім 23 учасникам (і ботам), які допомогли створити цей випуск!


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


У Windows оновіть або встановіть Visual Studio 2022 17.8 preview 3, щоб отримати .NET 8 RC2 із .NET MAUI (і 7.0.96).

 

Source




Posted on 25. July 2023

ASP.NET Core updates in .NET 8 Preview 6

Оновлення ASP.NET Core в .NET 8 Preview 6

.NET 8 Preview 6 вже доступна і містить багато нових чудових покращень в ASP.NET Core.

Ось короткий огляд новинок цієї попередній версії:

Покращено налагодження під час запуску

Blazor.

Прив'язка та валідація моделі форми з рендерингом на стороні сервера

Покращена навігація сторінками та обробка форм

Збереження наявних DOM-елементів за допомогою потокового рендерингу

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

Інтерактивний рендеринг з Blazor WebAssembly

Покращення розділів

Каскадний запит значень рядків до компонентів Blazor

Опція шаблону Blazor Web App для включення серверної інтерактивності

Консолідація шаблону Blazor

Метрики

Тестування метрик у додатках ASP.NET Core

Нові, покращені та перейменовані лічильники

Розробка API

Підтримка зв'язування складних форм у мінімальних API

Сервери та проміжне програмне забезпечення

Буферизація відповідей ядра HTTP.sys

Вихідний кеш на основі Redis

Щоб дізнатися більше про заплановані роботи над ASP.NET Core для .NET 8, дивіться повний опис ASP.NET Core для .NET 8 на GitHub.

Розпочнімо.

Щоб почати роботу з ASP.NET Core в .NET 8 Preview 6, встановіть .NET 8 SDK.

Якщо ви використовуєте Visual Studio на Windows, рекомендується встановити останню версію Visual Studio 2022 preview. Якщо ви використовуєте Visual Studio Code, ви можете спробувати нове розширення C# Dev Kit. Якщо ви використовуєте macOS, то можете працювати за допомогою Visual Studio для Mac 17.6.1, увімкнувши функцію preview для .NET 8 у Налаштуваннях.

Оновлення наявного проєкту

Щоб оновити наявний додаток ASP.NET Core з .NET 8 Preview 5 до .NET 8 Preview 6:

Оновіть цільовий фреймворк вашого додатка до net8.0.

Оновіть усі посилання на пакунок Microsoft.AspNetCore.* до версії 8.0.0-preview.6.*.

Оновіть усі посилання на пакунок Microsoft.Extensions.* до версії 8.0.0-preview.6.*.

Дивіться також повний список суттєвих змін в ASP.NET Core для .NET 8.

Покращений досвід налагодження під час запуску

У минулій попередній версії було представлено поліпшення налагодження для HttpContext. У .NET 8 Preview 6 покращено налагодження для типу WebApplication.

WebApplication - це спосіб за замовчуванням для налаштування та запуску додатків ASP.NET Core у Program.cs. Атрибути налагодження були застосовані до WebApplication, щоб виділити важливу інформацію, таку як налаштовані кінцеві точки, проміжне програмне забезпечення та значення IConfiguration у налагоджувачі вашого IDE.

.NET 7

WebApplication debugging before

.NET 8

WebApplication debugging after

Дивіться ASP.NET Core Налагодження GitHub для отримання додаткової інформації про покращення налагодження в .NET 8.

 

Blazor

Зв'язування та валідація моделі форми з рендерингом на стороні сервера

Новий режим рендерингу на стороні сервера Blazor тепер може моделювати зв'язування і перевіряти значення постів HTTP-форм.

Щоб прив'язати дані із запиту форми, застосуйте атрибут [SupplyParameterFromForm] до властивості компонента. Дані в запиті, які відповідають назві властивості, будуть прив'язані до цієї властивості. Властивість може бути примітивним типом, складним типом, колекцією або словником. Також підтримується перевірка на стороні сервера за допомогою анотацій даних.

 

Movie.cs

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

Вам більше не потрібно налаштовувати компонент CascadingModelBinder, щоб увімкнути прив'язку моделей. Тепер він налаштований для вас автоматично.

Покращена навігація сторінками та обробка форм

Тепер Blazor покращує навігацію сторінками та обробку форм шляхом перехоплення запиту, щоб застосувати відповідь до наявного DOM, максимально зберігаючи його. Покращення дозволяє уникнути необхідності повного завантаження сторінки й забезпечує користувачам значно простіший інтерфейс, подібний до односторінкового додатка (SPA), навіть якщо додаток все ще рендериться на стороні сервера.

У цій попередній версії покращена навігація та обробка форм ще не сумісна з одночасною наявністю на сторінці інтерактивних (серверних або WebAssembly) компонентів. Якщо ваш додаток використовує інтерактивні компоненти, розширену навігацію буде автоматично вимкнено. Це обмеження буде усунуто в наступній попередній версії перед випуском .NET 8 GA.

Збереження наявних DOM-елементів за допомогою потокового рендерингу

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

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

Тепер ви можете вказати режим рендерингу для екземпляра компонента за допомогою атрибута директиви @rendermode. Режим рендерингу буде застосовано до компонента та його дочірніх елементів. Наприклад, 

<Counter @rendermode="@RenderMode.Server" />


Щоб увімкнути використання call site @rendermode, переконайтеся, що у файлі проєкту встановлено версію мови Razor 8.0. Це буде оброблено внутрішньо у фреймворку і не буде необхідним, починаючи з наступного релізу. Для цього відредагуйте файл .csproj вашого проєкту, додавши в перший елемент <PropertyGroup> наступний рядок: <RazorLangVersion>8.0</RazorLangVersion>

Інтерактивний рендеринг з Blazor WebAssembly

Тепер ви можете увімкнути інтерактивний рендеринг компонентів за допомогою Blazor WebAssembly. Хоча ця опція ще не доступна у шаблоні вебпрограми Blazor, ви можете увімкнути її вручну.

Щоб увімкнути підтримку режиму рендерингу WebAssembly у вашому проєкті Blazor, додайте відповідні служби викликом app.Services.AddRazorComponents().AddWebAssemblyComponents() і додайте режим рендерингу WebAssembly викликом app.MapRazorComponents<App>().AddWebAssemblyRenderMode(). Будь-які компоненти, які ви хочете рендерити на WebAssembly, потрібно буде завантажити разом з усіма їхніми залежностями у браузер. Вам потрібно буде створити окремий проєкт Blazor WebAssembly для створення будь-якого специфічного коду для WebAssembly і посилатися на нього з вашого додатка Blazor.

Ви можете вказати режим інтерактивного рендерингу WebAssembly для компонента, додавши атрибут [RenderModeWebAssembly] до визначення компонента або вказавши @rendermode="@RenderMode.WebAssembly" у екземплярі компонента. Компоненти, які ви налаштували на рендеринг у WebAssembly, за замовчуванням також будуть попередньо рендеритися з сервера, тому переконайтеся, що ваші компоненти будуть коректно рендеритися в обох середовищах, або вимкніть попередній рендеринг при визначенні режиму рендерингу: [RenderModeWebAssembly(prerender: false)] або @rendermode="@(new WebAssemblyRenderMode(prerender: false)).

Ось приклад, що демонструє, як налаштувати інтерактивність на основі WebAssembly для компонента Counter, який виводиться зі сторінки Index .

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

Покращення розділів Blazor

Ми зробили наступні покращення у взаємодії розділів Blazor з іншими функціями Blazor:

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

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

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

Каскадний запит значень рядків до компонентів Blazor

 

Тепер ви можете отримувати значення параметрів рядка запиту в будь-якому компоненті, а не тільки в компонентах @page, використовуючи атрибут [SupplyParameterFromQuery]. Наприклад:

[SupplyParameterFromQuery]

public int PageIndex { get; set; }


Більше не потрібно додавати атрибут [Parameter] до будь-якої властивості, яка оголошує [SupplyParameterFromQuery].

Опція шаблону Blazor Web App для включення серверної інтерактивності

Шаблон Blazor Web App тепер надає опцію у Visual Studio для включення інтерактивності за допомогою режиму серверного рендерингу:

Blazor template option for server interactivity

Ця ж опція вже доступна з командного рядка:

dotnet new blazor --use-server


Консолідація шаблону Blazor

У рамках об'єднання різних моделей хостингу Blazor в єдину модель в .NET 8, також консолідовано кількість шаблонів проєктів Blazor. У цій попередній версії видалено шаблон Blazor Server і опцію "ASP.NET Core hosted" з шаблону Blazor WebAssembly. Обидва ці сценарії будуть представлені у вигляді опцій при використанні нового шаблону Blazor Web App.

 

Метрики

Тестування метрик у додатках ASP.NET Core

У попередній версії .NET 8 було представлено метрики ASP.NET Core. Тепер стало простіше тестувати метрики в додатках ASP.NET Core.

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

 

У прикладі нижче показано, як використовувати IMeterFactory і MetricCollector<T> (спрощений спосіб збору даних показників) у функціональному тесті ASP.NET Core:

Нові, покращені та перейменовані лічильники

ASP.NET продовжує покращувати підтримку метрик, додаючи нові лічильники та вдосконалюючи наявні. Це дозволить зробити додатки ASP.NET Core помітними в інформаційних панелях звітів і увімкнути користувацькі сповіщення.

Нові лічильники в цьому випуску:

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

diagnostics-handler-exception додано до проміжного програмного забезпечення обробки винятків. Лічильник повідомляє про те, як обробляються необроблені винятки, і містить інформацію про назву винятку та результат обробника.

http-server-unhandled-requests - це новий лічильник у хостингу ASP.NET Core. Він повідомляє, коли HTTP-запит досягає кінця конвеєра проміжного програмного забезпечення, не бувши обробленим додатком.

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

Покращені лічильники:

kestrel-connection-duration тепер містить протокол з'єднання HTTP і протокол TLS.

signalr-http-transport-current-connections тепер містить тип транспортного з'єднання.

Окрім того, на основі тестування ASP.NET Core за допомогою хмарних інструментів, було перейменовано всі лічильники ASP.NET Core, щоб надати в назву більше інформації. Лічильники було перейменовано, щоб їх можна було ідентифікувати лише за назвою та зменшити ймовірність конфліктів імен. Наприклад, request-duration було перейменовано на http-server-request-duration.

Розробка API

Підтримка зв'язування складних форм у мінімальних API

У .NET 8 Preview 4 розширено підтримку зв'язування форм у мінімальних API для обробки певних параметрів на основі форм без використання атрибута FromForm. Це було обмежено типами параметрів, включаючи IFormCollection, IFormFile і IFormFileCollection. Мінімальні API тепер підтримують прив'язку до форми для складніших сценаріїв, зокрема:

Колекцій, таких як List і Dictionary

 

Складних типів, таких як Todo або Project

У наведеному нижче прикладі показано мінімальну кінцеву точку, яка зв'язує багатокомпонентний ввід форми зі складним об'єктом. Він також показує, як використовувати служби захисту від підробок в ASP.NET для підтримки генерації та перевірки токенів від підробок в мінімальних API. Ключові моменти, на які слід звернути увагу в цьому прикладі, включають

Цільовий параметр має бути анотований атрибутом [FromForm], щоб відрізнити його від параметрів, які мають бути прочитані з JSON body.

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

Рекурсивне зв'язування не підтримується, тому тип Todo не містить рекурсивних посилань.

Сервери та проміжне програмне забезпечення

Буферизація відповідей ядра HTTP.sys

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

Кешування виводу на основі Redis

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

 

Щоб налаштувати кешування виводу на основі Redis, додайте посилання на пакет Microsoft.Extensions.Caching.StackExchangeRedis, а потім налаштуйте необхідні служби, викликавши app.Services.AddStackExchangeRedisOutputCache(...). Доступні опції конфігурації ідентичні наявним опціям розподіленого кешування на основі Redis. Ви можете надати власний сервер Redis або скористатися послугами хостингу, наприклад, Azure Cache для Redis.





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 у файлі вашого проєкту.