Миграция на .NET Standard 2.1
Перенос существующего приложения Doconut.NETStandard с версии 26.7.0 на 26.8.0
Doconut имеет два разных интеграционных решения для .NET Standard. Они используют одно и то же имя пакета Doconut.NETStandard, поэтому определите поколение по версии и API в приложении перед изменением пакетов, настроек запуска, лицензий или ресурсов браузера.
Версия — это развилочка
Оба поколения публикуются под одним и тем же идентификатором пакета. Только версия различает их:
| Версия | Цель | API |
|---|---|---|
| 26.7.0 и ниже | netstandard2.0 | предыдущий API |
| 26.8.0 и выше | netstandard2.1 | текущий API |
Повышение номера версии — это обновление. Нет отдельного пакета для установки и нет совместимого shim — 26.8.0 имеет иной набор API. Ожидайте ошибок компиляции после повышения версии; остальная часть руководства — это их список.
Какую интеграцию вы используете?
| Если проект содержит… | Поколение |
|---|---|
new Viewer(_cache, _accessor, ...) | Предыдущее |
viewer.OpenDocument(...) (синхронный) | Предыдущее |
viewer.InitCache() | Предыдущее |
UseDoconut(new DoconutOptions { ... }) | Предыдущее |
UseDoconutWebFarm(...) / WebFarmOptions | Предыдущее |
Viewer.DoconutLicense(...) или Viewer.SetLicensePlugin(...) | Предыдущее |
viewer.Converter.GetConverter() | Предыдущее |
using Doconut.Configs; / using Doconut.Models; | Предыдущее |
Вручную скопированный docViewer.js, documentLinks.js или docViewer.UI.js | Предыдущее |
builder.Services.AddDoconut(...) | Текущее |
app.UseDoconutResources() и app.UseDoconut() без аргументов | Текущее |
Viewer, предоставляемый внедрением зависимостей | Текущее |
await viewer.OpenDocumentAsync(...) | Текущее |
Если обе колонки встречаются в одном приложении, рассматривайте миграцию как незавершённую. Не отправляйте токен документа через ресурсы или middleware из другого поколения.
Сначала проверьте целевую платформу
Это жёсткое ограничение, а не предпочтение. Текущий пакет нацелен на netstandard2.1:
| Хост | Может использовать 26.8.0 |
|---|---|
| .NET Core 3.0 или позже (включая .NET 5/6/7/8) | Да |
| .NET Framework, любой версии | Нет |
.NET Framework не может ссылаться на библиотеку netstandard2.1. Если приложение работает на .NET Framework, остановитесь здесь и используйте пакет Doconut.NETFramework; начиная с версии 26.9.0 он требует .NET Framework 4.7.2. Оба референсных приложения для этого релиза нацелены на net8.0.
Перед миграцией
- Создайте ветку и развертываемую резервную копию существующего приложения.
- Запишите точные версии основных и плагин‑пакетов.
- Составьте инвентарь всех вызовов
new Viewer(...), вызововInitCache(), загрузки лицензий, сопоставленийUseDoconutWebFarm, контроллеров конверсии, скопированных скриптов Doconut, пользовательских действий панели инструментов, обратных вызовов viewer и конечных точек открытия документов. - Сохраните текущие файлы
.licи секреты развертывания вне системы контроля версий. - Соберите репрезентативный набор PDF, Office, изображений, CAD, email, DICOM, документов с возможностью поиска, защищённых паролем и аннотированных.
- Запишите текущие параметры таймаута сессии, поведения безопасности, шрифтов и настроек платформы.
Перенесите одну среду перед изменением продакшна. Текущая интеграция меняет время жизни сервисов, маршрутизацию запросов, владение сессией, доставку клиентских ресурсов и — если вы используете ферму — способ доставки страниц в браузер.
1. Пространства имён: почти всё перенесено в корень
Типы конфигурации были распределены по четырём пространствам имён. Теперь они все находятся в Doconut.
| До | Сейчас |
|---|---|
using Doconut.Configs.View; | using Doconut; |
using Doconut.Models; | using Doconut; |
using Doconut.Configs; | using Doconut; |
using Doconut.Configs.Cloud; | using Doconut.Clouds; |
using Doconut.Configs.Conversion; | не изменено |
using Doconut.Middleware; | не изменено |
Имена типов не изменились: WordConfig, PdfConfig, ExcelConfig, CssConfig, ScriptConfig, CloudUploadConfig, AzureConfig, CDNConfig, FileShareConfig и остальные по‑прежнему доступны. В большинстве файлов единственное изменение — удаление двух строк using.
Doconut.Configs.Editor (BaseConfigEditor, PdfConfigEditor) был удалён и не имеет замены в этом пакете. Если ваше приложение ссылалось на эти типы, планируйте эту часть отдельно и не рассматривайте её как часть миграции.
2. Совместимость пакетов и лицензий
Заменяйте или обновляйте основной пакет осознанно; не полагайтесь на идентичный ID пакета для выбора нового API. Команда по умолчанию устанавливает последнюю стабильную версию:
dotnet add package Doconut.NETStandardДля воспроизводимой миграции к выпуску, проверенному в этом руководстве, укажите версию как отдельный параметр:
dotnet add package Doconut.NETStandard --version 26.8.0Держите каждый плагин Doconut на той же версии, что и основной пакет — Doconut.NETStandard.Converter и Doconut.NETStandard.Dicom. Текущая интеграция загружает лицензии один раз во время AddDoconut(), используя следующий приоритет:
LicenseStream > LicenseContent > LicensePath > automatic discoveryАвтоматическое обнаружение ищет файлы Doconut.Viewer.lic и сопутствующие Doconut.Viewer.<Capability>.lic. Предыдущие статические вызовы Viewer.DoconutLicense(...) и Viewer.SetLicensePlugin(...) больше не являются механизмом запуска, как и List<string> путей лицензий, которые принимал старый конструктор Viewer. Переместите лицензию в DoconutOptions, храните сопутствующие файлы вместе при использовании автоматического обнаружения, перезапустите приложение после изменения лицензии и проверьте возможности через IDoconutLicenseService.
Не следует полагать, что наличие старой лицензии плагина подтверждает право на текущую сборку плагина. Тестируйте Viewer, Search, Annotation, Converter и DICOM отдельно, используя утверждённые артефакты выпуска.
3. Запуск и внедрение зависимостей
Ранее Viewer создавался для каждого запроса, а параметры передавались в middleware:
// Предыдущая интеграция — только для сравнения; не компилируйте этот код с текущим SDK.
var viewer = new Viewer(_cache, _accessor);
// …
appBranch.UseDoconut(new DoconutOptions { UnSafeMode = false, ShowDoconutInfo = false });Текущая интеграция регистрирует Doconut один раз и получает Viewer через внедрение зависимостей:
builder.Services.AddDoconut(options =>
{
options.UnsafeMode = false; // обратите внимание на изменение написания: UnSafeMode → UnsafeMode
options.ShowDoconutInfo = false;
options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // состояние сессии требует кэш (MVC/Razor Pages уже добавляют один)
builder.Services.AddSession();
app.UseSession();
app.UseDoconutResources();
app.UseDoconut();Viewer является транзиентным сервисом. Менеджер сессий документа и его кэш владеют более долгоживущим состоянием документа, а не конкретным внедрённым экземпляром Viewer.
Три момента, которые нужно перенести:
new Viewer(cache, accessor)удалён. ВнедритеDoconut.Viewerв ваш контроллер или используйте@inject Doconut.Viewer Viewerв Razor‑view.UseDoconutResources()заменяет ручную привязкуapp.UseMiddleware<EmbeddedResourceMiddleware>()и должен выполняться до ветки документа.UnSafeMode→UnsafeMode. Переименование на один символ будет обнаружено компилятором.
Когда UnsafeMode установлен в false, SDK проверяет токен сессии относительно исходного запроса, поэтому AddSession() / UseSession() всё равно должны находиться в конвейере, а UseSession() — перед веткой.
Методы, которые больше не существуют
| Было | Сейчас |
|---|---|
viewer.OpenDocument(path, config, options) | await viewer.OpenDocumentAsync(path, config, options) |
viewer.InitCache() | удалено — ничего вручную разогревать не нужно; удалите вызов и любые флаги типа «уже инициализировано» |
viewer.ExportToPng(sharedPath) | см. §7 |
viewer.ExportToCloud(cloudConfig) | см. §7 |
using var v = new Viewer(...); v.CloseDocument(t) | viewer.CloseDocument(token) у внедрённого экземпляра |
4. Middleware и маршрутизация ресурсов
UseDoconut() теперь не принимает аргументов. Форма ветки MapWhen менять не требуется — меняется только middleware внутри неё:
app.UseDoconutResources(); // ДО ветки
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconut());В текущем конвейере:
- вызывайте
UseSession()до Doconut, пока включена защита сессии; - вызывайте
UseDoconutResources()доUseDoconut(); - держите
ResourcesPath, сгенерированные URL‑ы ресурсов и клиентскийResPathсогласованными; - держите сопоставленную ветку и клиентский
BasePathсогласованными.
MiddlewarePath — проверенная конфигурация; она сама по себе не создаёт ветку ASP.NET Core.
5. Конструирование и жизненный цикл Viewer
Удалите кэши Viewer, принадлежащие приложению. В Viewer больше нет ничего, что стоило бы сохранять: он не содержит состояния документа, а кэш сеанса владеет всем, что живёт дольше запроса. Внедрите его в конечную точку, Razor‑страницу, контроллер или область сервисов приложения:
app.MapPost("/api/open", async (Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
return Results.Ok(new { token });
});Возвращённый токен идентифицирует серверную сессию документа. Обращайтесь с ним как с токеном‑носителем: не регистрируйте его, не сохраняйте и не передавайте в аналитические системы.
6. Открытие и закрытие документов
Замените синхронный OpenDocument(...) на OpenDocumentAsync(...):
// Текущая интеграция: Viewer получен из DI, а открытие документа происходит асинхронно.
var token = await viewer.OpenDocumentAsync(path, new PdfConfig { AllowSearch = true });Текущие перегрузки принимают путь к файлу или поток, необязательную конфигурацию формата, необязательный DocOptions и токен отмены. Явно закрывайте серверную сессию, когда браузер больше её не нуждается:
viewer.CloseDocument(token);Удалите любые вызовы InitCache() и соответствующий флаг — нечего прогревать вручную. Не переиспользуйте токен, созданный предыдущей библиотекой после перехода: открывайте каждый документ заново через текущий API.
7. Web farm → distributed: самое большое изменение
UseDoconutWebFarm и WebFarmOptions больше не существуют. Если ваше приложение вызывает их, этот раздел — ваше обновление; если нет, переходите к §8.
Ранее один middleware делал всё: он обслуживал предварительно отрисованные изображения из общей папки и опросил пока другой узел ещё записывал их.
// Предыдущая интеграция — один вызов, неявная координация через файловую систему.
appBranch.UseDoconutWebFarm(new WebFarmOptions
{
Path = Path.Combine(env.WebRootPath, "webfarm"),
PageWaitTimeSeconds = 180,
StartWaitFromPage = 5,
});Та же задача теперь разделена на две явные части. Сторона записи — узел, открывающий документ, публикует весь набор артефактов (страницы, информацию о документе, поисковый индекс, метаданные) в общий ресурс:
var result = await _publisher.PublishAsync( // DistributedDocumentPublisher, внедренный через DI
pathToFile,
new FileShareConfig
{
Location = CloudLocation.FileShare,
RootPath = @"\\fileserver\doconut", // тот же каталог, который вы используете сегодня
UsePerTokenSubfolders = true,
},
config,
documentOptions,
new DistributedDocumentPublishOptions
{
CleanUpStagingDirectory = true,
FirstPagePriority = true,
});
return Content(result.Token);Сторона чтения — любой узел обслуживает из общего ресурса:
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconutCloud<FileShareCloudHandler>(options =>
{
options.Location = CloudLocation.FileShare;
options.CloudUploadConfig = /* тот же FileShareConfig, что выше */;
}, "/"));| До | Сейчас |
|---|---|
WebFarmOptions.Path | FileShareConfig.RootPath |
PageWaitTimeSeconds / StartWaitFromPage | удалено — заменено FirstPagePriority на стороне записи плюс FileShareConfig.ReadReadyPollMs на стороне чтения |
viewer.OpenDocument(...) затем viewer.ExportToPng(share) | один вызов PublishAsync(...) |
DocOptions.IsWebfarm / WebfarmPath | по‑прежнему присутствует, назван IsWebFarm / WebFarmPath — но не нужен в пути публикации |
Ваша топология не меняется. Укажите RootPath на тот же UNC‑ресурс, и каждый узел будет работать так же, как сейчас. Изменяется лишь то, что публикация становится вызываемой операцией, а не побочным эффектом рендеринга.
Обе части должны согласовываться. Если
RootPathилиUsePerTokenSubfoldersразличаются между публикующим и обработчиком, другой узел вернёт 404. Сформируйте конфигурацию в одном вспомогательном методе и вызывайте её с обеих сторон.
PageWaitTimeSeconds = 180 означал «блокировать до трёх минут в ожидании появления страницы». Замена явная: с FirstPagePriority = true страница 1 становится доступной сразу, а последующие страницы отвечают HTTP 202 Accepted, пока не будут записаны. Встроенный viewer автоматически повторяет запросы, когда установлен retryOn409. Клиент, который не делает повторов, будет видеть сломанные плитки для ещё рендерящихся страниц.
Полная схема, включая фоновую публикацию и билеты доступа, описана в разделе Распределённые развертывания.
8. Конвертация — это плагин, и гораздо меньше
Зарегистрируйте плагин, затем внедрите фасад DocumentConverter:
builder.Services.AddDoconut(o => o.AddPlugin<ConverterPlugin>());// Предыдущая интеграция
var converter = viewer.Converter.GetConverter();
var config = new WordConfigConverter { TargetFormat = WordConfigConverter.EnTargetFormat.PDF };
var result = converter.Convert(stream, SourceFormatConverter.DOCX, config);
// Текущая интеграция
var result = await _converter.ConvertAsync(stream, ".docx", ConversionTarget.Pdf, null, ct);Что это заменяет:
SourceFormatConverter— удалён. Передавайте расширение файла как строку, включая точку.- Типы
*ConfigConverterдля каждой семьи (WordConfigConverter,ExcelConfigConverter, …), каждый с вложенным перечислениемEnTargetFormat— удалены. Теперь существует одно перечислениеConversionTargetдля каждой семьи. viewer.Converter.GetConverter()— удалён. ВнедритеDoconut.DocumentConverter.
ConvertAsync возвращает поток, поддерживающий поиск, поэтому return File(result, mime, name) работает напрямую — копия MemoryStream, необходимая в старом коде, не нужна. В поставляемом примере это удалило переключатель расширений с 68 случаями и десять почти одинаковых контроллеров.
Смотрите Плагин конвертера для полного описания.
9. Облачные провайдеры
UseDoconutCloud стал обобщённым. Провайдер теперь передаётся как типовой аргумент вместо значения Location, переключаемого внутри middleware:
// Предыдущая интеграция
appBranch.UseDoconutCloud(new CloudOptions { Location = CloudLocation.CDN, ... });
// Текущая интеграция
branch.UseDoconutCloud<CDNCloudHandler>(options =>
{
options.Location = CloudLocation.CDN;
options.CloudUploadConfig = new CDNConfig { DoconutCdnUrl = "..." };
}, "/");Классы конфигурации остались без изменений, за исключением пространства имён (Doconut.Configs.Cloud → Doconut.Clouds): AzureConfig, AmazonConfig, GoogleCloudConfig, DropBoxConfig, RedisConfig, CDNConfig, FTPConfig, а также новый FileShareConfig. Обработчики называются <Provider>CloudHandler.
Обработчик CDN является только для чтения — он обслуживает то, что уже находится на CDN; загрузка не производится.
10. Объекты конфигурации, названия которых изменились
| Раньше | Сейчас |
|---|---|
DoconutOptions.UnSafeMode | UnsafeMode |
DocOptions.IsWebfarm | IsWebFarm |
DocOptions.WebfarmPath | WebFarmPath |
DocOptions.ImageResolution | всё ещё присутствует, но устарел — задавайте разрешение в конфигурации формата вместо этого |
DocOptions также получает IsSecured.
Текущий API также более строго разделяет ответственности по сравнению с предыдущим, поэтому проверьте, что каждая настройка находится в объекте, которому она теперь принадлежит:
| Область | Текущий тип |
|---|---|
| Пути middleware, лицензирование, регистрация плагинов | DoconutOptions |
| Пароль, тайм‑аут, безопасность, водяной знак | DocOptions |
| Отрисовка формата и DPI | PdfConfig, WordConfig, ExcelConfig и другие типы BaseConfig |
| Настройки виджета браузера по умолчанию | ViewerConfig или эквивалентные параметры JavaScript |
| Сгенерированные CSS и скрипты | CssConfig и ScriptConfig |
| Общее хранилище и облачные провайдеры | FileShareConfig и остальные конфигурации из Doconut.Clouds |
Не переносите DocOptions.ImageResolution как управление отрисовкой. Он устарел; задавайте BaseConfig.ImageResolution в конфигурации конкретного формата. Пересмотрите все значения по умолчанию, вместо того чтобы предполагать, что прежняя конфигурация ведёт себя так же.
11. Клиентский просмотрщик — два изменения, которые тихо не работают
Оба этих изменения оставляют сервер в полностью рабочем состоянии. Ваш документ рендерится, страница выглядит правильно, и в консоли браузера ничего не появляется. Прочитайте этот раздел, даже если ваш C# компилируется с первой попытки.
Обратные вызовы просмотрщика теперь являются опциями, а не глобальными функциями
Предыдущий просмотрщик вызывал ваши обработчики по имени, формируя глобальное имя функции из идентификатора контейнера. Достаточно было объявить function ctlDoc_OnViewerReady() на странице с <div id="div_ctlDoc">. Текущий просмотрщик принимает явные обратные вызовы в объекте опций и больше не ищет эти глобальные функции:
objctlDoc = $("#div_ctlDoc").docViewer({
// ... ваши текущие параметры ...
onViewerBusy: ctlDoc_OnViewerBusy, // было найдено по имени
onViewerReady: ctlDoc_OnViewerReady, // было найдено по имени
onCopy: ctlDoc_Copy, // было ctlDoc_Copy(text)
onAutoLoadStatus: ctlDoc_AutoLoadStatus // было ctlDoc_AutoLoadStatus(page)
});Почему это проблематично: старый вызов был обёрнут в пустой catch, который глотал все ошибки. Теперь ваши функции просто не вызываются, и об ошибке ничего не сообщается. Обычный симптом — индикатор загрузки, который никогда не останавливается, потому что функция, скрывающая его, была ctlDoc_OnViewerReady. Сам документ при этом в порядке.
Полный список опций: onPageLoading, onPageLoaded, onThumbnailClicked, onPageClicked, onDoubleClick, onViewerBusy, onViewerReady, onViewerError, onCopy, onAnnSaved, onAnnSaveError, onAnnLoaded, onAnnClosed, onAutoLoadStatus, onThumbsShown и onError. Обратного вызова при клике по ссылке нет: обработка гиперссылок встроена и управляется параметром showHyperlinks.
ResPath должен указывать на префикс ресурса
ResPath: '', // РАНЬШЕ — ресурсы поступали из корня приложения
ResPath: 'doconut-res/images', // СЕЙЧАС — префикс, который монтирует UseDoconutResources()Если вы изменили префикс через DoconutOptions.ResourcesPath, используйте это значение вместо него.
12. Панель инструментов Viewer, поиск и аннотации
Не переносите старые скрипты по одному. Текущие справочные приложения собирают один полный пакет страницы:
- выпустить CSS Viewer и лицензированный CSS поиска/аннотаций с помощью
ReferenceCss; - отрисовать панель инструментов Viewer, принадлежащую приложению;
- отрисовать
searchBarMount,annBarMountи необходимый монтировщик Viewer; - выпустить скрипты Viewer и лицензированных модулей с помощью
ReferenceScripts; - загрузить собственный вспомогательный скрипт панели инструментов приложения;
- инициализировать один
objViewer; - инициализировать лицензированные ленты поиска и аннотаций;
- вызвать
attach(objViewer)для каждой ленты; - открыть документ и вызвать
objViewer.View(token).
Поиск и аннотации — это модули, присоединённые к тому же Viewer, а не независимые панели инструментов. Основная панель принадлежит хост‑приложению; ленты поиска и аннотаций являются встроенными, ограниченными возможностями ресурсами.
Удаляйте вручную скопированные файлы, такие как documentLinks.js и docViewer.UI.js, только после того, как текущая страница начнёт работать с ресурсами, выпущенными ReferenceCss и ReferenceScripts.
13. Регистрация плагинов
Статические методы лицензирования плагинов не регистрируют текущие плагины. Установите и зарегистрируйте каждый выпущенный пакет явно:
builder.Services.AddDoconut(options =>
{
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddPlugin<Doconut.Plugins.Dicom.DicomPlugin>();
});AddDoconut() проверяет зарегистрированные возможности плагинов при запуске. Converter и DICOM — это выпущенные плагины .NET Standard. Обычные поиск и аннотации — встроенные лицензированные функции, а не пакеты AddPlugin<TPlugin>().
14. Сессия и безопасность документов
Текущая интеграция привязывает документы к непрозрачным токенам и кэшированным сессиям. При значении по умолчанию UnsafeMode = false UseDoconut() добавляет безопасность доступа к документу, и хост должен настроить ASP.NET‑сессию:
builder.Services.AddDistributedMemoryCache(); // состояние сессии требует кэш (MVC/Razor Pages уже добавляют один)
builder.Services.AddSession();
app.UseSession();Оставляйте DocOptions.IsSecured = true, если только проверенный дизайн не требует иного. Никогда не используйте UnsafeMode = true как миграционный ярлык на отдельном узле. Тестируйте запросы без токена, с повреждённым токеном, с истёкшим токеном и с токеном из другой сессии браузера.
В ферме запрос страницы может попасть на узел, который никогда не видел начального запроса, поэтому проверка per‑session отклонит его. Это единственный случай, когда UnsafeMode = true допустим — и его необходимо сочетать с подписанными билетами доступа через AddDoconutDistributedDocumentSecurity, а не использовать отдельно. См. Распределённые развертывания.
Примечание к именованию
Во всех фреймворках класс называется Viewer. Если вы встречаете DocumentViewer в старых фрагментах кода или сторонних статьях, такого типа никогда не было в SDK.
15. Предлагаемый порядок работы
- Убедитесь, что хостовый фреймворк может использовать netstandard2.1. Если нет — остановитесь.
- Обновите пакет до 26.8.0 и соберите проект. Разберите ошибки компиляции — большинство связаны со строками
usingв §1. - Перенесите инициализацию в
AddDoconut()и вызовы middleware в их новый порядок (§3, §4). - Внедрите
Viewerтам, где вы его создавали, сделайтеOpenDocumentасинхронным и удалитеInitCache()(§5, §6). - Если вы используете веб‑ферму, выполните §7 — единственная часть, требующая редизайна, а не переименования.
- Если вы конвертируете документы, выполните §8.
- Выполните §11 — изменения на клиенте. Это те изменения, которые не объявятся сами.
- Откройте реальный документ в браузере и наблюдайте за индикатором загрузки. Зеленая сборка ничего не доказывает: лицензирование, регистрация плагинов, путь к ресурсам и обратные вызовы viewer могут провалиться только во время выполнения. Для фермы проверьте, что документ, опубликованный на одном узле, обслуживается другим.
Тестирование миграции
Как минимум, проверьте:
- запуск приложения с производственной лицензией и всеми зарегистрированными плагинами;
- CSS/скрипты Viewer и все запросы изображений страниц по выбранным путям;
- открытие документа, навигация, масштабирование, миниатюры, печать и явное закрытие;
- поиск в документе с текстом и отсутствие возможности поиска в файле, содержащем только изображения;
- загрузка, сохранение, экспорт аннотаций и управление возможностями;
- обнаружение целей конвертера, вывод, загрузка и состояние водяного знака;
- страницы, кадры и анимация DICOM; технические метаданные недоступны в этом пакете;
- документы, защищённые паролем, пользовательские шрифты, нелатинский текст и настроенные тайм‑ауты;
- отклонение токенов между сессиями и поведение при истёкшей сессии;
- для фермы: опубликовать на одном узле, запросить позднюю страницу с другого и убедиться, что Viewer повторно запрашивает ответы
202, а не отображает сломанные плитки; - мобильные устройства, тёмный режим и путь обратного прокси в продакшене.
План отката
Сохраните предыдущий артефакт развертывания, соответствующие пакеты, файлы лицензий и скопированные ресурсы браузера вместе. Безопасный откат переключает всю генерацию приложения; он не смешивает сервер предыдущего поколения с текущими скриптами или текущий сервер с вызовами new Viewer(...).
Перед переключением задокументируйте:
- слот развертывания или артефакт, используемый для отката;
- влияние на общие хранилища, если таковое имеется — артефакты, опубликованные в версии 26.8.0, не используются предыдущим промежуточным ПО веб‑фермы;
- как будут инвалидированы активные сессии документов;
- проверка состояния (health check) и тестовый документ, используемый для решения об откате;
- кто может восстановить предыдущий набор пакетов и конфигурацию.
Унаследованная документация
Переведённое предыдущее руководство доступно по ссылке Унаследованная настройка .NET Standard. Предыдущий шлюз интеграции объясняет те же сигналы идентификации и ссылается обратно на это руководство по миграции.
Сохраняйте исторический URL в закладках и служебных запросах, пока установки netstandard2.0 ещё существуют. Он описывает другую генерацию и не перенаправляется на текущий API.
Была ли эта страница полезной?