💡Примечание: Следующий контент был написан на основе Optimizely CMS 13 Preview 2 и может неточно отражать окончательную версию.
В рамках подготовки Stott Security и Stott Robots Handler для PaaS CMS 13 мне пришлось вернуться к ключевым функциям моих надстроек, использующих определения сайтов. Эти надстройки позволяют пользователю определять конфигурации robots.txt, llms.txt и security.txt в глобальном масштабе, для каждого сайта и для каждого хоста. В результате мне нужно иметь возможность считывать данные о различных конфигурациях сайта.
Доступ к определениям сайта/приложения
Поскольку CMS 13 взяла на себя инициативу SaaS и задумалась о более компонуемых архитектурах, произошел сдвиг от мышления о «сайтах» к размышлению о «приложениях». Также наблюдается переход к использованию двух разных конфигураций приложений. Существует традиционный «в процессе» Приложение CMS, которое представлено Веб-сайт класс, и есть «безголовый» приложение, которое представлено УдаленныйВеб-сайт сорт. Эти два приложения наследуют Приложение сорт.
Существующие ISiteDefinitionRepository сейчас устарел, но на данный момент работает и возвращает только в процессе приложения. Для доступа к обоим типам приложений вам необходимо использовать новый интерфейс Репозиторий приложений. Этот новый репозиторий предоставляет следующие методы для перечисления приложений:
// In-process applications
var data = await applicationRepository.ListAsync();
// Headless applications
var data = await applicationRepository.ListAsync();
// All applications
var data = await applicationRepository.ListAsync();
var data = await applicationRepository.ListAsync();
Еще одно ключевое изменение заключается в том, что поле GUID Id больше не существует. ISiteDefinitionRepository все еще работает, идентификатор заполняется пустым GUID в целях совместимости. Новые объекты используют имя Вместо этого оно генерируется как исправленная версия отображаемого имени в нижнем регистре при создании, а затем становится неизменяемым свойством.
Еще одно долгожданное изменение с Репозиторий приложений — это переход к асинхронным API, который упрощает написание неблокирующего и масштабируемого кода, особенно в сценариях с высокой пропускной способностью.
⚠️ Предупреждение о миграции: Если вы ранее вводили конфигурацию с помощью SiteDefinition.Id, вам понадобится стратегия миграции для сопоставления устаревших GUID с Application.Name. Не существует однозначной замены, и новое имя после создания становится неизменным.
Решение текущего приложения
Исторически сложилось так, что доступ к текущему веб-сайту для вашей текущей страницы будет осуществляться через SiteDefinition.Current. Это больше не доступно, и вместо этого нам нужно использовать IApplicationResolver вместо. Это обеспечивает доступ к следующим методам:
// Retrieve the application based on a host name
var result = applicationResolver.GetByHostname(hostName, fallbackToDefault);
var result = await applicationResolver.GetByHostnameAsync(hostName, fallbackToDefault, cancellationToken);
// Retrieve the application based on a given content reference
var app = applicationResolver.GetByContent(contentReference, fallbackToDefault);
var app = await applicationResolver.GetByContentAsync(contentReference, fallbackToDefault, cancellationToken);
// Retrieve the application based on the current HTTP Context
var app = GetByContext();
var app = await GetByContextAsync(cancellationToken);
Декомпиляция DefaultApplicationResolver Я вижу, что GetByContext методы на самом деле просто оборачивают GetByContent и GetByHostName методы и попытайтесь сделать это сначала с помощью Content. Если ваша функциональность должна работать вне маршрута содержимого, то лучше получить приложение напрямую по имени хоста, просто имейте в виду, что это возвращает ApplicationHostResolution а не Приложение.
public async ValueTask GetByContextAsync(CancellationToken cancellationToken = default(CancellationToken))
{
Application application = null;
ContentReference routedContentLink = _routedContentLinkResolver.RoutedContentLink;
if (!ContentReference.IsNullOrEmpty(routedContentLink))
{
application = await GetByContentAsync(routedContentLink, fallbackToDefault: true, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
if (application == null)
{
string hostName = _requestHostResolver.HostName;
(application, _) = await GetByHostnameAsync(hostName, fallbackToDefault: true, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}
return application;
}
Краткое содержание
CMS 13 заменяет традиционную концепцию сайтов приложениями, поддерживая как внутрипроцессные, так и автономные модели. Хотя устаревшие API-интерфейсы сайтов все еще существуют для обеспечения совместимости, новые разработки должны использовать IApplicationRepository и IApplicationResolver.
Переход от идентификаторов сайтов на основе GUID к неизменяемым именам приложений является наиболее значительным изменением и имеет реальные последствия для хранения и миграции конфигурации. Хотя это требует некоторой корректировки, новая модель приложения обеспечивает более чистую и гибкую основу для современных архитектур CMS.
Я OMVP, автор и сопровождающий Стотт Секьюрити и Стотт Роботс-обработчик для Optimizely CMS 12. Весь мой контент можно найти на сайте https://www.stott.pro/
30 января 2026 г.
По теме

