События
Чемпионат мира Power BI DataViz
14 февр., 16 - 31 мар., 16
С 4 шансами войти, вы можете выиграть пакет конференции и сделать его в LIVE Grand Finale в Лас-Вегасе
ПодробнееЭтот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
Примечание
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Важно!
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Прогрессивное веб-приложение Blazor — это одностраничное приложение (SPA), которое использует API и функциональные возможности современного браузера, реализуя свойственное классическим приложениям поведение.
Blazor WebAssembly — это стандартизированная клиентская платформа веб-приложений с поддержкой API любых браузеров, в том числе API-интерфейсы прогрессивных веб-приложений (PWA), требуемых для реализации следующих возможностей:
Слово прогрессивное используется для описания таких приложений по следующим причинам:
При создании приложения Blazor WebAssembly установите флажок Прогрессивное веб-приложение.
При необходимости PWA можно настроить для приложения, созданного из шаблона проекта ASP.NET Core HostedBlazor WebAssembly . Сценарий прогрессивного веб-приложения не зависит от модели размещения.
В этом разделе приводятся указания по преобразованию существующего приложения Blazor WebAssembly в PWA.
В файле проекта приложения сделайте следующее:
Добавьте указанное ниже свойство ServiceWorkerAssetsManifest
в PropertyGroup
:
...
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
</PropertyGroup>
Добавьте указанный ниже элемент ServiceWorker
в ItemGroup
:
<ItemGroup>
<ServiceWorker Include="wwwroot\service-worker.js"
PublishedContent="wwwroot\service-worker.published.js" />
</ItemGroup>
Для получения статических ресурсов воспользуйтесь одним из следующих подходов:
Создайте отдельный новый проект PWA с помощью команды dotnet new
в командной оболочке:
dotnet new blazorwasm -o MyBlazorPwa --pwa
В предыдущей команде параметр -o|--output
создает новую папку для приложения с именем MyBlazorPwa
.
Если вы не преобразуете приложение для использования в последнем выпуске, передайте параметр -f|--framework
. В следующем примере создается приложение для ASP.NET Core версии 5.0:
dotnet new blazorwasm -o MyBlazorPwa --pwa -f net5.0
Перейдите по приведенному ниже URL-адресу в репозиторий GitHub для ASP.NET Core, который содержит ссылки на справочные материалы и ресурсы для ветви main
. Выберите выпуск, с которым вы работаете, в раскрывающемся списке Switch branches/tags (Переключение ветвей или тегов).
Blazor WebAssembly Папка шаблона wwwroot
проекта (dotnet/aspnetcore
ветвь репозитория main
GitHub)
Примечание
По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Скопируйте следующие файлы из папки wwwroot
источника в созданном вами приложении или из справочных ресурсов в репозитории GitHub dotnet/aspnetcore
в папку wwwroot
приложения:
icon-192.png
icon-512.png
manifest.webmanifest
service-worker.js
service-worker.published.js
В файле wwwroot/index.html
приложения:
Добавьте элементы <link>
для манифеста и значка приложения:
<link href="manifest.webmanifest" rel="manifest" />
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
<link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
Перейдите к репозиторию ASP.NET Core GitHub по следующему URL-адресу, который ссылается на v7.0.0
источник и ресурсы тега. Если вы используете версию ASP.NET Core позже 7.0, измените селектор версии документа в верхней части этой статьи, чтобы просмотреть обновленные рекомендации по этому разделу. Выберите выпуск, с которым вы работаете, в раскрывающемся списке Switch branches/tags (Переключение ветвей или тегов).
Blazor WebAssembly Папка шаблона wwwroot
проекта (v7.0.0
тег)
Примечание
По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Скопируйте следующие файлы из папки wwwroot
источника в созданном вами приложении или из справочных ресурсов в репозитории GitHub dotnet/aspnetcore
в папку wwwroot
приложения:
favicon.png
icon-192.png
icon-512.png
manifest.json
service-worker.js
service-worker.published.js
В файле wwwroot/index.html
приложения:
Добавьте элементы <link>
для манифеста и значка приложения:
<link href="manifest.json" rel="manifest" />
<link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" />
<link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
Добавьте следующий тег <script>
в закрывающий тег </body>
сразу после тега скрипта blazor.webassembly.js
:
...
<script>navigator.serviceWorker.register('service-worker.js');</script>
</body>
При посещении приложения, созданного с помощью шаблона PWA, пользователи могут установить приложение в меню "Пуск" операционной системы, док-станции или home экрана. Порядок применения этого параметра зависит от того, какой браузер используется. В классических версиях браузеров на основе Chromium, таких как Microsoft Edge или Chrome, в строке URL-адреса появляется кнопка Добавить. После того как пользователь нажмет кнопку Добавить, отобразится диалоговое окно подтверждения.
В iOS посетители могут установить прогрессивное веб-приложение с помощью кнопки Поделиться в браузере Safari, а также используя параметр Добавить на главный экран. В браузере Chrome для Android для этой цели следует нажать кнопку Меню в правом верхнем углу окна, а затем выбрать команду Добавить на экран Home.
После установки приложение будет открываться в отдельном окне без адресной строки.
Чтобы настроить заголовок окна, цветовую схему, значок или другие сведения, используйте файл manifest.json
в каталоге wwwroot
проекта. Схема этого файла соответствует веб-стандартам. Дополнительные сведения см . в веб-документах MDN: манифест веб-приложения.
Приложения, созданные с помощью параметра шаблона PWA, поддерживают работу в автономном режиме. Для этого пользователь должен сначала посетить приложение при наличии подключения к сети. Браузер автоматически скачает и кэширует все ресурсы, необходимые для его работы в автономном режиме.
Важно!
Поддержка разработки может помешать типовому циклу разработки, предусматривающему внесение изменений и их тестирование. Поэтому поддержка работы в автономном режиме доступна только для опубликованных приложений.
Предупреждение
Если вы планируете распространять прогрессивное веб-приложение с поддержкой автономного режима, следует обратить внимание на несколько важных предупреждений и предостережений. Эти сценарии присущи всем поддерживающим автономную работу прогрессивным веб-приложениям и не являются специфичными для Blazor. Не забудьте прочитать и понять эти предостережения, прежде чем делать предположения о том, как работает приложение с поддержкой автономного режима.
Чтобы ознакомиться с принципами поддержки автономного режима:
Публикация приложения. Дополнительные сведения см. в статье Размещение и развертывание ASP.NET Core Blazor.
Разверните приложение на сервере, который поддерживает протокол HTTPS, и получите доступ к приложению в браузере по его защищенному HTTPS-адресу.
Откройте средства разработки браузера и убедитесь, что для узла на вкладке Приложение зарегистрирована рабочая роль службы.
Перезагрузите страницу и просмотрите вкладку "Сеть". Кэш рабочей роли службы или памяти перечислены в качестве источников для всех ресурсов страницы:
Чтобы убедиться, что для загрузки приложения браузеру не требуется доступ к сети:
Поддержка работы в автономном режиме с помощью рабочей роли службы является веб-стандартом, не относящимся к Blazor. Дополнительные сведения о рабочих службах см . в веб-документации MDN: API рабочей роли службы. Дополнительные сведения о распространенных шаблонах использования для работников службы см. в Разделе Google Web: Жизненный цикл рабочей роли службы.
Шаблон прогрессивного веб-приложения Blazor создает два файла рабочей роли службы:
wwwroot/service-worker.js
, который используется во время разработки;wwwroot/service-worker.published.js
, который используется после публикации приложения.Чтобы использовать общую логику для этих двух файлов рабочих ролей службы, рассмотрите следующий подход.
self.importScripts
, чтобы загрузить общую логику в оба файла рабочей роли службы.Встроенная рабочая роль службы service-worker.published.js
выполняет разрешение запросов с применением стратегии первичного обращения к кэшу. Это означает, что даже при наличии доступа к сети или нового содержимого на сервере во всех возможных случаях рабочая роль службы отдает предпочтение возвращаемому из кэша содержимому.
Такая стратегия полезна по следующим причинам.
Во-первых, за счет этого повышается надежность. Состояние доступа к сети сложно определить однозначно, поскольку пользователь не всегда просто находится в подключенном или автономном режиме.
Именно поэтому API navigator.onLine
браузера не может считаться надежным источником, на который следует полагаться в приложении.
Во-вторых, это позволяет гарантировать корректность. При создании кэша автономных ресурсов рабочая роль службы хэширует содержимое, чтобы гарантировать получение полного и согласованного моментального снимка ресурсов по состоянию на один конкретный момент времени. В дальнейшем этот кэш используется в качестве атомарной единицы. Запрашивать более новые версии ресурсов из сети нецелесообразно, поскольку все данные, которые требуются, уже хранятся в кэше. Любые другие данные могут стать причиной несогласованности и несовместимости, например при попытке использовать версии сборок .NET, которые не компилировались вместе.
Если при развертывании новой версии рабочей роли службы необходимо запретить получение service-worker-assets.js
браузера из своего HTTP-кэша, например, чтобы устранить временные ошибки проверки целостности при развертывании новой версии рабочей роли службы, обновите регистрацию рабочей роли службы, wwwroot/index.html
указав updateViaCache
значение none:
<script>
navigator.serviceWorker.register('/service-worker.js', {updateViaCache: 'none'});
</script>
Для наглядности прогрессивное веб-приложение с предпочтительным автономным режимом работы можно рассматривать как устанавливаемое мобильное приложение. Оно запускается немедленно, независимо от наличия сетевого подключения, однако при этом логика установленного приложения извлекается из моментального снимка на определенный момент времени, который может содержать устаревшие данные.
На основе шаблона прогрессивного веб-приложения Blazor создаются приложения, которые пытаются автоматически выполнить обновление в фоновом режиме при наличии работающего сетевого подключения каждый раз, когда приложение посещает пользователь. Этот процесс реализуется следующим образом:
service-worker-assets.js
. В нем перечислены все статические ресурсы, которые требуются для работы приложения в автономном режиме, например сборки .NET, файлы JavaScript и каскадные таблицы стилей, в том числе хэши содержимого. Рабочая роль службы загружает список ресурсов и использует его для определения ресурсов, которые требуется кэшировать.service-worker.js
и service-worker-assets.js
в фоновом режиме. Файлы сравниваются побайтово с существующей установленной рабочей ролью службы. Если сервер возвращает измененное содержимое для любого из этих файлов, рабочая роль службы пытается установить собственную новую версию.service-worker-assets.js
. Эта логика реализуется в функции onInstall
в файле service-worker.published.js
.Настроить этот процесс можно, используя логику рабочей роли службы. Все перечисленные выше варианты не являются специфичными для Blazor, однако описывают стандартный способ использования шаблона прогрессивного веб-приложения. Дополнительные сведения см . в веб-документах MDN: API рабочей роли службы.
Как описывается выше в разделе Стратегия первичного обращения к кэшу, по умолчанию рабочая роль службы применяет стратегию первичного обращения к кэшу, то есть пытается по возможности всегда использовать кэшированное содержимое. Если для отдельного URL-адреса кэшированное содержимое отсутствует (например, в случае запроса данных из серверного API), рабочая роль службы использует обычные сетевые запросы, которые выполняются успешно только при наличии доступа к серверу. Эта логика реализуется в функции onFetch
в файле service-worker.published.js
.
Если компоненты приложения Razor запрашивают данные из серверных API и вам требуется удобный пользовательский интерфейс для обработки сбоев, связанных с отсутствием доступа к сети, то соответствующую логику необходимо реализовать в самих компонентах приложения. Например, используйте try/catch
для запросов HttpClient.
Рассмотрим, что происходит при первом переходе пользователя к URL-адресу, например к /counter
, или по любой другой прямой ссылке в приложении. В таких случаях вам не нужно возвращать кэшированное содержимое как /counter
. Вместо этого нужно загрузить в браузер содержимое, кэшированное как /index.html
, для запуска приложения Blazor WebAssembly. Такие начальные запросы называются запросами навигации в отличие от следующих запросов:
subresource
для получения изображений, таблиц стилей или других файлов;fetch/XHR
для получения данных API.По умолчанию рабочая роль службы использует для обработки запросов навигации специальную логику. Рабочая роль службы разрешает такие запросы путем возврата кэшированного содержимого для /index.html
, независимо от того, какой URL-адрес запрашивается. Эта логика реализуется в функции onFetch
в файле service-worker.published.js
.
Если для некоторых URL-адресов в вашем приложении должен возвращаться подготавливаемый к просмотру на сервере код HTML (то есть для обслуживания /index.html
не должен использоваться кэш), вам потребуется изменить логику рабочей роли службы. Если все URL-адреса, содержащие /Identity/
, требуется обрабатывать как обычные сетевые запросы к серверу, следует изменить логику функции onFetch
в файле service-worker.published.js
. Найдите следующий код:
const shouldServeIndexHtml = event.request.mode === 'navigate';
Измените код следующим образом:
const shouldServeIndexHtml = event.request.mode === 'navigate'
&& !event.request.url.includes('/Identity/');
Если этого не сделать, то, независимо от наличия сетевого подключения, рабочая роль службы будет перехватывать запросы к таким URL-адресам и разрешать их с помощью /index.html
.
Добавьте в проверку конечные точки для внешних поставщиков проверки подлинности. В следующем примере в проверку добавляется /signin-google
для проверки подлинности Google:
const shouldServeIndexHtml = event.request.mode === 'navigate'
&& !event.request.url.includes('/Identity/')
&& !event.request.url.includes('/signin-google');
Для среды не требуется никаких действий, где содержимое Development
всегда извлекается из сети.
Если в вашем проекте определено свойство MSBuild ServiceWorkerAssetsManifest
, средства сборки Blazor создадут манифест ресурса рабочей роли службы с указанным именем. По умолчанию шаблон прогрессивного веб-приложения создает файл проекта со следующим свойством.
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
Этот файл помещается в выходной каталог wwwroot
, откуда браузер может извлекать его посредством запроса /service-worker-assets.js
. Чтобы просмотреть содержимое этого файла, откройте /bin/Debug/{TARGET FRAMEWORK}/wwwroot/service-worker-assets.js
в текстовом редакторе. Не вносите изменения в этот файл, поскольку он создается заново при каждой сборке.
Списки манифестов:
wwwroot
приложения, такие как изображения, таблицы стилей и файлы JavaScript. К ним также относятся статические веб-ресурсы, предоставляемые в составе внешних проектов и пакетов NuGet.Чтобы управлять получением и кэшированием этих ресурсов в рабочей роли службы, измените логику функции onInstall
в файле service-worker.published.js
. Рабочая роль службы извлекает и кэширует файлы, соответствующие типичным расширениям имен веб-файлов, таким как .html
.pdb
, .css
.js
и , а также типы файлов, относящиеся к Blazor WebAssemblyфайлам (все версии) и .dll
.wasm
файлам (ASP.NET Core в .NET 7 или более ранней версии).
Чтобы включить другие ресурсы, отсутствующие в каталоге wwwroot
приложения, определите дополнительные записи ItemGroup
MSBuild, как показано в следующем примере.
<ItemGroup>
<ServiceWorkerAssetsManifestItem Include="MyDirectory\AnotherFile.json"
RelativePath="MyDirectory\AnotherFile.json" AssetUrl="files/AnotherFile.json" />
</ItemGroup>
В метаданных AssetUrl
указывается относительный URL-адрес, который браузер должен использовать при получении ресурса в кэш. При этом имя оригинального исходного файла на диске может не учитываться.
Важно!
Добавление ServiceWorkerAssetsManifestItem
не приводит к публикации файла в каталог wwwroot
приложения. Управление выходными данными публикации следует организовать отдельно. В результате добавления ServiceWorkerAssetsManifestItem
в манифесте ресурса рабочей роли службы лишь появляется дополнительная запись.
Как и любые аналоги, прогрессивные веб-приложения Blazor WebAssembly поддерживают получение push-уведомлений от внутреннего сервера. Сервер может отправлять такие уведомления в любое время, даже если приложение не используется активно (например, если другой пользователь выполняет действие, о котором требуется оповестить).
Механизм отправки push-уведомлений не зависит от Blazor WebAssembly, так как он реализуется на внутреннем сервере, который может использовать любую технологию. Для отправки push-уведомлений с сервера ASP.NET Core рекомендуется использовать методику, аналогичную описываемой в рамках семинара по проекту Blazing Pizza.
Механизм приема и отображения push-уведомлений на стороне клиента также реализуется независимо от Blazor WebAssembly в файле JavaScript рабочей роли службы. Рекомендуем обратиться к семинару, посвященному проекту Blazing Pizza.
Поддержка работы в автономном режиме требуется не для всех приложений. С ее реализацией сопряжены определенные сложности, решение которых не всегда целесообразно.
Поддержка автономной работы как правило требуется лишь в следующих случаях:
localStorage
или индексированной базе данных.Кроме того, поддержка работы в автономном режиме для прогрессивных веб-приложений сопряжена с рядом дополнительных сложностей. Разработчикам следует внимательно изучить предостережения, приведенные в разделах ниже.
В процессе разработки каждое изменение, как правило, должно сразу отражаться в браузере, не дожидаясь обновления в фоновом режиме. Поэтому шаблон прогрессивного веб-приложения Blazor обеспечивает поддержку автономной работы только после публикации приложения.
При создании автономного приложения недостаточно для тестирования приложения в Development
среде. Вам придется проверить приложение в опубликованном состоянии, чтобы понять, как оно будет вести себя при различных состояниях сети.
Обновления будут выполняться только после того, как пользователь выйдет из приложения на всех вкладках. Как поясняется в разделе Обновления в фоновом режиме, после развертывания и обновления приложения браузер получит обновленные файлы рабочей роли службы, чтобы запустить процесс обновления.
Что удивляет многих разработчиков, что, даже когда это обновление завершается, он не вступают в силу, пока пользователь не перейдет на все вкладки. Недостаточно обновить вкладку, отображающую приложение, даже если она является единственной вкладкой, отображающей приложение. Пока пользователь не закроет приложение полностью, новая рабочая роль службы будет оставаться в состоянии ожидания активации. Это не зависит Blazorот стандартного поведения веб-платформы.
Соответственно, многие разработчики сталкиваются с проблемами при попытке протестировать обновления рабочей роли службы или кэшированных автономно ресурсов. Открыв средства разработчика в браузере, вы можете увидеть нечто подобное:
Рабочая роль будет находиться в состоянии ожидания до тех пор, пока список "клиентов" (т. е. вкладок или окон, в которых отображается приложение) не опустеет. Это необходимо для обеспечения согласованности. Согласованность означает получение всех ресурсов из одного атомарного кэша.
При тестировании изменений может быть удобно выбрать ссылку skipWaiting, как показано на предыдущем снимке экрана, а затем перезагрузить страницу. Можно автоматизировать этот процесс для всех пользователей, реализовав в коде рабочей роли службы пропуск этапа "ожидания" с немедленной активацией обновления. Если пропустить этап ожидания, согласованное получение ресурсов из одного и того же экземпляра кэша не гарантируется.
Как правило, разработчики веб-приложения ожидают, что пользователи будут работать только с его последней развернутой версией, поскольку это характерно для традиционной модели распространения. Тем не менее прогрессивное веб-приложение с предпочтительным автономным режимом работы в этом отношении больше похоже на собственное мобильное приложение, пользователи которого далеко не всегда работают с последней версией.
Как описано в разделе "Фоновые обновления ", после развертывания обновления в приложении каждый существующий пользователь продолжает использовать предыдущую версию по крайней мере для одного дальнейшего посещения, так как обновление происходит в фоновом режиме и не активируется до тех пор, пока пользователь после этого не перейдет. Кроме того, в этом случае предыдущей используемой версией не обязательно будет та, которую вы развернули в прошлый раз. В зависимости от того, когда пользователь последний раз выполнял обновление, это может быть любая ранее существовавшая версия.
Таким образом, если внешние и внутренние компоненты приложения должны использовать согласованную схему для работы с запросами к API, это может привести к возникновению проблем. Соответственно, развертывать изменения схемы API, не предусматривающие обратную совместимость, можно только после того, как вы убедитесь, что все пользователи выполнили обновление. Также в таких случаях можно явно запретить использование несовместимых старых версий приложения. Это требование к сценарию аналогично тому, которое применяется для собственных мобильных приложений. При развертывании существенных изменений в серверных API пользователи, не выполнившие обновление, столкнутся со сбоями в работе клиентского приложения.
Соответственно, по возможности не следует развертывать существенные изменения в серверных API. Если это все же необходимо, рекомендуется использовать стандартные API рабочей роли службы, такие как ServiceWorkerRegistration, для определения актуальности версии приложения и блокировки его старых версий.
Как описывается выше в разделе Поддержка страниц, подготавливаемых к просмотру на сервере, чтобы обойти поведение рабочей роли службы и предотвратить возврат содержимого /index.html
для всех запросов навигации, измените логику рабочей роли службы.
Как описывается выше в разделе Управление кэшированием ресурсов, файл service-worker-assets.js
создается в процессе сборки и содержит список всех ресурсов, которые должна получать и кэшировать рабочая роль службы.
Так как этот список включает в себя все wwwroot
, в том числе содержимое, предоставленное внешними пакетами и проектами, необходимо быть осторожным, чтобы не поместить туда слишком много содержимого. Если каталог wwwroot
содержит несколько миллионов изображений, рабочая роль службы попытается получить и кэшировать их все, что приведет к перегрузке сети и, скорее всего, закончится сбоем.
Реализуйте произвольную логику, ограничивающую получение и кэширование содержимого манифеста, внеся соответствующие изменения в функцию onInstall
в файле service-worker.published.js
.
Шаблон PWA можно использовать вместе с проверкой подлинности. Прогрессивные веб-приложения с поддержкой автономной работы также могут обеспечивать проверку подлинности при наличии у пользователя начального подключения к сети.
В случае отсутствия сетевого подключения пользователь не сможет пройти проверку подлинности или получить маркеры доступа. Попытка посетить страницу входа без сетевого доступа приводит к возникновению сообщения об ошибке сети. Необходимо организовать работу пользователя в автономном режиме таким образом, чтобы для выполнения задач при отсутствии сетевого подключения не требовались маркеры доступа или проверка подлинности. Либо должны быть предусмотрены способы минимизировать последствия сбоев в таких случаях. Если реализовать это в приложении невозможно, следует задуматься, действительно ли в нем необходима поддержка работы в автономном режиме.
Если приложение, предназначенное для работы в сети и в автономном режиме, снова подключено к сети:
Чтобы создать автономное приложение PWA, взаимодействующее с проверкой подлинности:
Описанные выше подходы демонстрируются в примере приложения CarChecker
. Ознакомьтесь со следующими частями приложения:
OfflineAccountClaimsPrincipalFactory
(Client/Data/OfflineAccountClaimsPrincipalFactory.cs
)LocalVehiclesStore
(Client/Data/LocalVehiclesStore.cs
)LoginStatus
(Client/Shared/LoginStatus.razor
)Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
События
Чемпионат мира Power BI DataViz
14 февр., 16 - 31 мар., 16
С 4 шансами войти, вы можете выиграть пакет конференции и сделать его в LIVE Grand Finale в Лас-Вегасе
ПодробнееОбучение
Схема обучения
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization