Делаем сайт на SharePoint 2010. Оптимизация

Сайт на SharePoint 2010. Брендинг
Сайт на SharePoint 2010. Оптимизация
Сайт на SharePoint 2010. Брендинг Wiki-страниц
Сайт на SharePoint 2010. Построение иерархии страниц

Сегодня я расскажу про оптимизацию интернет-сайтов на базе MS SharePoint 2010 для достижения максимальной производительности. Этот пост будет продолжением предыдущего, посвященного брендингу SharePoint, т.е. оптимизация по большей части будет касаться интерфейса посетителей, а не редакторов/модераторов/администраторов.

С сайта www.allfreelogo.com

Веб-части (WebParts)

Начну с простого, а именно с оптимизации отображения веб-частей на странице. В SharePoint у каждой веб-части есть название, меню и граница. Ничего из этого для посетителю сайта не понадобится. Скрыть эту "обертку" можно, указав свойство веб-части ChromeType равным PartChromeType.None. Т.к. мы должны оставить нетронутым интерфейс редакторов, придется реализовывать данный функционал в нашем классе FluentWebPartPage. Сначала продублируем приватное свойство SPWebPartManager в нашем классе:

  1. private SPWebPartManager SPWebPartManager
  2. {
  3.     get
  4.     {
  5.         return (WebPartManager.GetCurrentWebPartManager(thisas SPWebPartManager);
  6.     }
  7. }

Теперь на событии OnLoad мы зададим тип хрома для всех веб-частей на странице:

  1. protected override void OnLoad(EventArgs e)
  2. {
  3.     base.OnLoad(e);
  4.     // Если пользователь не анонимный, то выходим
  5.     if (!IsAnonymous) return;
  6.     // Перебираем все веб-части и задаем им тип хрома
  7.     foreach(var webPart in SPWebPartManager.WebParts.Cast<WebPart>())
  8.     {
  9.         webPart.ChromeType = PartChromeType.None;
  10.     }
  11. }

Теперь каждая веб-часть "обрамлена" незначительным HTML-кодом:

  1. <table class="s4-wpTopTable" border="0" cellpadding="0" cellspacing="0" width="100%">
  2.     <tbody>
  3.         <tr>
  4.             <td valign="top">
  5.                 <div webpartid="[WebPartGuid]" haspers="false" id="WebPartWPQ3"
  6.                width="100%" class="ms-WPBody noindex" allowdelete="false" style="">
  7.                     <!-- Содержимое веб-части -->
  8.                 </div>
  9.             </td>
  10.         </tr>
  11.     </tbody>
  12. </table>

Если развивать это направление дальше, то можно переопределить рендеринг веб-частей и зон веб-частей, чтобы, например, уйти от таблиц.

Скрипты

Следующий шаг будет касаться клиентского кода, а именно его минимизации. Здесь я опишу два способа.

ScriptLink.IsMinimalMode

Первый способ касается свойства IsMinimalMode объекта ScriptLink:

  1. internal static bool IsMinimalMode
  2. {
  3.     get
  4.     {
  5.         return ((HttpContext.Current.Items["sp-MinimalScriptKey"
  6.                   as string) == "MinimalScriptMode");
  7.     }
  8.     set
  9.     {
  10.         string str = value ? "MinimalScriptMode" : string.Empty;
  11.         HttpContext.Current.Items["sp-MinimalScriptKey"] = str;
  12.     }
  13. }
  14.  

Таким образом, чтобы задействовать этот режим, нам достаточно в метод FluentWebPartPage.SetAnonymousView следующую строчку кода:

  1. HttpContext.Current.Items["sp-MinimalScriptKey"] = "MinimalScriptMode";

В этом случае мы оставляем за SharePoint право решать какие срипты загружать а какие нет. Мы просто декларируем свое желание минимизировать клиентский код.

ScriptLink.GetScriptLinks

Второй способ более радикален. Здесь уже мы будем решать какие скрипты загружать, а какие нет. SharePoint получает список скриптов, подлежащих регистрации на странице, вызывая метод ScriptLink.GetScriptLinks(). Вот его код:

  1. private static List<ScriptLinkInfo> GetScriptLinks()
  2. {
  3.     List<ScriptLinkInfo> list = 
  4.         HttpContext.Current.Items["sp-scriptlinks"
  5.             as List<ScriptLinkInfo>;
  6.     if (list == null)
  7.     {
  8.         list = new List<ScriptLinkInfo>();
  9.         HttpContext.Current.Items["sp-scriptlinks"] = list;
  10.     }
  11.     return list;
  12. }

Сам класс ScriptLinkInfo помечен как internal, что ограничивает нас в его применении, поэтому придется использовать рефлексию. Регистрация скриптов на странице в SharePoint происходит на событии OnPreRender, т.е. возможность повлиять на итоговый набор скриптов у нас есть. Класс ScriptLinkInfo содержит следующие свойства:

  1. public bool Defer { getset; }
  2. public string Filename { get; }
  3. public string Language { get; }
  4. public bool LoadAfterUI { getset; }
  5. public bool Localizable { get; }
  6. public bool OnDemand { getset; }
  7. public string OnDemandKey { getset; }
  8. public IEnumerable<string> Sections { get; }

Я покажу пример который будет искать скрипт по его имени (Filename) и, если он не помечен как загружаемый по требованию (поле OnDemand), то удалять его из коллекции скриптов. Также можно задействовать локализацию и другие свойства для более сложной логики.

  1. /// <summary>
  2. /// Удаление скрипта из списка на загрузку
  3. /// </summary>
  4. /// <param name="scriptName">Название скрипта</param>
  5. /// <param name="restrictIsDemand">Удалять даже если загрузка по требованию</param>
  6. private static void RestrictClientScript(string scriptName, bool restrictIsDemand)
  7. {
  8.     // Берем скрипты, подлежащие регистрации на странице
  9.     var scripts = HttpContext.Current.Items[SPScriptLinks] as IList;
  10.     // Выходим, если scripts не существует
  11.     if (scripts == nullreturn;
  12.     var fileIndex = -1;
  13.     // Беребираем все объекты в коллекции
  14.     for (var i = 0; i < scripts.Count; i++)
  15.     {
  16.         // Текущий объект ScriptLinkInfo
  17.         var file = scripts[i];
  18.         var type = file.GetType();
  19.         // Ищем в типе свойства Filename и OnDemand
  20.         var prop = type.GetProperty("Filename");
  21.         if (prop == nullcontinue;
  22.         var propDemand = type.GetProperty("OnDemand");
  23.         if (propDemand == nullcontinue;
  24.         // Получаем значение свойства Filename
  25.         var jsName = prop.GetValue(file, null).ToString();
  26.         // Получаем значение свойства OnDemand
  27.         // По умолчанию считаем OnDemand = false
  28.         var jsOnDemandFlag = propDemand.GetValue(file, nullis bool
  29.                                     ? (bool) propDemand.GetValue(file, null)
  30.                                     : false;
  31.         // Если скрипт загружется по требованию, то пропускаем его
  32.         // если restrictIsDemand = false
  33.         if (jsOnDemandFlag && !restrictIsDemand) continue;
  34.         // Если имя скрипта не совпадает со значение параметра scriptName, 
  35.         // то передаем управление следующе   итерации
  36.         if (string.Compare(scriptName, jsName, true) != 0) continue;
  37.         // Запоминаем позицию скрипта в коллекции и выходим из цикла
  38.         fileIndex = i;
  39.         break;
  40.     }
  41.     // Если в коллеции был найден скрипт, то удалем его
  42.     if (fileIndex != -1)
  43.         scripts.RemoveAt(fileIndex);
  44.     // Указываем новую коллекцию скриптов
  45.     HttpContext.Current.Items[SPScriptLinks] = scripts;
  46. }

Теперь можно использовать этот метод на событии OnPreRender:

  1. protected override void OnPreRender(EventArgs e)
  2. {
  3.     base.OnPreRender(e);
  4.     RestrictClientScript("core.js"true);
  5.     RestrictClientScript("init.js"true);
  6. }

Стили

На набор стилей, которые будут зарегистрированы на странице повлиять не получится, поэтому мы просто уберем из master-страницы для посетителей контрол CssLink и заменим его на стандартный HTML-элемент link.

Ссылки на css в master-странице для редакторов сайта:

  1. <SharePoint:CssLink runat="server" Version="4"/>

Ссылки на css в master-странице для посетителей сайта:

  1. <link rel="stylesheet" type="text/css" media="Screen"
  2. href="/_layouts/ZhukBlog.InternetSite.Branding/Styles/Screen.css" />
  3. <link rel="stylesheet" type="text/css" media="Print"
  4. href="/_layouts/ZhukBlog.InternetSite.Branding/Styles/Print.css" />

Так как стандартный интерфейс SharePoint не используется для интернет пользователей, то можно и, я считаю, вполне разумно создать свой css-файл с нуля.

Результаты

Результат оптимизации по сравнению со стандартным интерфейсом SharePoint 2010 более чем показателен:

Размер содержимого страницы

Незначительное уменьшение размера css-файлов связано стем, что файл Screen.css является копией файла CoreV4.css за исключением того, что из него удалены комментарии.

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

Время генерации страницы

Здесь под временем загрузки страницы я имею ввиду время её генерации. Эти значения я получал с помощью Developer Dashboard.

Кэширование

Также для повышения производительности можно задействовать кэширование. Подробно кэширование в этом посте я описывать не буду, т.к. это уже административное воздействие на производительность SharePoint. Просто приведу ссылки на статьи в MSDN для ознакомления:
Кэширование вывода и профили кэша - стандартный механизм ASP.NET. Если в двух словах, то это "обмен" места ОЗУ на время ЦП. Если Front-End сервером два и более то есть вероятность возникновения несогласованности.
Дисковое кэширование для больших двоичных объектов (BLOB) - механизм, при задействовании которого SharePoint сохраняет на диск файлы, запрашиваемые из списков/библиотек, чтобы в дальнейшем снять нагрузку с SQL Server.
Кэширование объектов - сохранения элементов объектной модели SharePoint в памяти. Также касается и Linq to SharePoint.

Виталий Жуков

Виталий Жуков

SharePoint архитектор, разработчик, тренер, Microsoft MVP (Office Development). Более 15 лет опыта работы с SharePoint, Dynamics CRM, Office 365, и другими продуктами и сервисами Microsoft.

Смотрите также

Новый сайт группы SharePoint. Как это работает

Новый сайт группы SharePoint. Как это работает

SharePoint 2019 Preview

SharePoint 2019 Preview

Управление большими списками/библиотеками в SharePoint

Управление большими списками/библиотеками в SharePoint

SharePoint 2013/2016. Настройка хлебных крошек

SharePoint 2013/2016. Настройка хлебных крошек

SharePoint 2016. Кастомизация меню SuiteBar

SharePoint 2016. Кастомизация меню SuiteBar

SharePoint 2016. Кастомизация SuiteBar

SharePoint 2016. Кастомизация SuiteBar

Домашняя страница сайта SharePoint

Домашняя страница сайта SharePoint

Презентация и скрипты со встречи сообщества по SharePoint и Office 365

Презентация и скрипты со встречи сообщества по SharePoint и Office 365

PowerShell DSC. SharePoint

PowerShell DSC. SharePoint

PowerShell DSC. Сертификат для шифрования пароля

PowerShell DSC. Сертификат для шифрования пароля

PowerShell DSC. Учетные записи

PowerShell DSC. Учетные записи

Встреча сообщества по SharePoint и Office 365

Встреча сообщества по SharePoint и Office 365

SharePoint 2016. QR-code

SharePoint 2016. QR-code

Возможности SharePoint 2010/2013/2016

Возможности SharePoint 2010/2013/2016

Gmail IIS SMTP relay

Gmail IIS SMTP relay

SharePoint 2016. Извещения мозаикой

SharePoint 2016. Извещения мозаикой

Сертификация SharePoint по-новому

Сертификация SharePoint по-новому

SharePoint. Получение списка сайтов

SharePoint. Получение списка сайтов

Планирование фермы SharePoint

Планирование фермы SharePoint

Обзор SharePoint Education. Часть 3

Обзор SharePoint Education. Часть 3

SharePoint Excel Services. Отображение диаграммы на странице

SharePoint Excel Services. Отображение диаграммы на странице

SharePoint 2016 Release Candidate

SharePoint 2016 Release Candidate

Обзор SharePoint Education. Часть 2

Обзор SharePoint Education. Часть 2

Обзор SharePoint Education. Часть 1

Обзор SharePoint Education. Часть 1

SharePoint 2013 Образование. Установка и настройка

SharePoint 2013 Образование. Установка и настройка

SharePoint 2016 IT Preview

SharePoint 2016 IT Preview

SharePoint и SMS. Часть 2. Регистрация OMS-сервиса

SharePoint и SMS. Часть 2. Регистрация OMS-сервиса

SharePoint и SMS. Часть 1. Создание OMS веб-сервиса

SharePoint и SMS. Часть 1. Создание OMS веб-сервиса

SharePoint Day: 14 декабря, Москва

SharePoint Day: 14 декабря, Москва

RuSUG 17.10.2013. Презентация с моего доклада о новом поиске в SharePoint 2013

RuSUG 17.10.2013. Презентация с моего доклада о новом поиске в SharePoint 2013

SharePoint 2013 Ribbon API. Версии 14.3 и 15.4

SharePoint 2013 Ribbon API. Версии 14.3 и 15.4

Встреча RuSUG 17-го октября

Встреча RuSUG 17-го октября

SharePoint 2013. Служба ServiceDesk за 8 часов либо правильный проект

SharePoint 2013. Служба ServiceDesk за 8 часов либо правильный проект

SharePoint 2010/2013. Локализация данных

SharePoint 2010/2013. Локализация данных

Список возможностей SharePoint 2013

Список возможностей SharePoint 2013

SharePoint 2013. Типы полей

SharePoint 2013. Типы полей

SharePoint 2013 Enterprise Search. Часть 2. Создание обработчика контента

SharePoint 2013 Enterprise Search. Часть 2. Создание обработчика контента

SharePoint 2013 Enterprise Search. Часть 1. Логическая архитектура

SharePoint 2013 Enterprise Search. Часть 1. Логическая архитектура

SharePoint Ribbon. Создание многоуровневого меню

SharePoint Ribbon. Создание многоуровневого меню

SharePoint Ribbon. Использование ColorPicker'а

SharePoint Ribbon. Использование ColorPicker'а

Разработка для SharePoint. Как это было и как это будет

Разработка для SharePoint. Как это было и как это будет

SharePoint. История социализма за 10 лет

SharePoint. История социализма за 10 лет

SharePoint 2013 Preview

SharePoint 2013 Preview

Использование штрихкодов в SharePoint 2010

Использование штрихкодов в SharePoint 2010

Unable to locate the xml-definition for FieldName

Unable to locate the xml-definition for FieldName

SharePoint 2010. Апрельский накопительный пакет обновлений

SharePoint 2010. Апрельский накопительный пакет обновлений

Не удалось найти XML-файл в указанном расположении

Не удалось найти XML-файл в указанном расположении

Служба синхронизации профилей пользователей. Ошибки

Служба синхронизации профилей пользователей. Ошибки

Делаем сайт на SharePoint 2010. Построение иерархии страниц

Делаем сайт на SharePoint 2010. Построение иерархии страниц

Делаем сайт на SharePoint 2010. Брендинг Wiki-страниц

Делаем сайт на SharePoint 2010. Брендинг Wiki-страниц

Делаем сайт на SharePoint 2010. Брендинг

Делаем сайт на SharePoint 2010. Брендинг

Обработка большого количества элементов в SharePoint

Обработка большого количества элементов в SharePoint

Получение уникальных значений поля списка

Получение уникальных значений поля списка

DeskWork 5. Функциональность (продолжение)

DeskWork 5. Функциональность (продолжение)

Сокрытие информации о пользователе создавшем/изменившем элемент

Сокрытие информации о пользователе создавшем/изменившем элемент

Error : Code blocks are not allowed in this file

Error : Code blocks are not allowed in this file

SharePoint Client Object Model. Управляемый код

SharePoint Client Object Model. Управляемый код

Использование контрола HtmlEditor. Часть 3

Использование контрола HtmlEditor. Часть 3

SharePoint 15 SDK

SharePoint 15 SDK

PeopleEditor и Internet Explorer 9

PeopleEditor и Internet Explorer 9

Использование контрола HtmlEditor. Часть 2

Использование контрола HtmlEditor. Часть 2

Использование контрола HtmlEditor. Часть 1

Использование контрола HtmlEditor. Часть 1

Пропадающий контрол выбора представления списка

Пропадающий контрол выбора представления списка

Развертывание библиотеки документов с файлами

Развертывание библиотеки документов с файлами

Отключенные учетные записи и PeoplePicker

Отключенные учетные записи и PeoplePicker

Пропадающий TextBox в Telerik Reporting

Пропадающий TextBox в Telerik Reporting

Длительные операции в SharePoint. Request timed out

Длительные операции в SharePoint. Request timed out

Длительные операции в SharePoint. Изнутри

Длительные операции в SharePoint. Изнутри

Длительные операции в SharePoint. Снаружи

Длительные операции в SharePoint. Снаружи

DeskWork. Версия 5.1

DeskWork. Версия 5.1

DeskWork 5. Часть 2. Функциональность

DeskWork 5. Часть 2. Функциональность

DeskWork 5. Часть 1. Установка

DeskWork 5. Часть 1. Установка

SharePoint 2010. Random ListItem

SharePoint 2010. Random ListItem

Custom ListDefinition. Отключаем диалоги

Custom ListDefinition. Отключаем диалоги

SharePoint 2010 UpdatePanel. Request Notification

SharePoint 2010 UpdatePanel. Request Notification

Получение размера вложений SPListItem'а

Получение размера вложений SPListItem'а

SharePoint 2010. Переопределение форм типа содержимого

SharePoint 2010. Переопределение форм типа содержимого

SharePoint 2007/2010. Привязываем EventReceiver к типу содержимого

SharePoint 2007/2010. Привязываем EventReceiver к типу содержимого

Изменяем appSettings в config-файле

Изменяем appSettings в config-файле

SharePoint 2010. Добавляем сборку в пакет

SharePoint 2010. Добавляем сборку в пакет

SharePoint 2007/2010. The security validation for this form is invalid

SharePoint 2007/2010. The security validation for this form is invalid

SharePoint 2010. JavaScript IntelliSence

SharePoint 2010. JavaScript IntelliSence

SharePoint 2010. Локализация SiteDefinition

SharePoint 2010. Локализация SiteDefinition

SharePoint 2007. Получение данных из нескольких списков и узлов

SharePoint 2007. Получение данных из нескольких списков и узлов

SharePoint 2007. Максимальное/минимальное значение поля в списке

SharePoint 2007. Максимальное/минимальное значение поля в списке

SharePoint 2007. Свой контрол на панели свойств веб-парта

SharePoint 2007. Свой контрол на панели свойств веб-парта

SharePoint 2007. База данных содержимого

SharePoint 2007. База данных содержимого

SharePoint 2007. Проверка на наличие элемента в списке

SharePoint 2007. Проверка на наличие элемента в списке