Cross-site навигация в Sharepoint. Часть 2

В моей предыдущей статье (на английском) я написал как можно реализовать cross-site навигацию для сайтов, доступных в WSS (это не включает в себя сайты публикации – очень распространенный тип сайтов). Как показывает статистика указанный пост пользуется большой популярностью. Поэтому я пока решил отложить другие темы и закончить серию статей о навигации (раз эта тема настолько востребована). Прежде чем читать дальше я рекомендую ознакомиться с другим моим постом The basics of navigation in Sharepoint (тоже, к сожалению, только на английском), в котором я описал основные компоненты и архитектуру навигации в Sharepoint.

Итак перед нами стоит следующая задача: предположим у нас есть сайт коллекция (SPSite) с несколькими подсайтами (SPWeb). Мы хотим, чтобы при переходе между сайтами верхняя навигация сохранялась (как вы увидите ниже с описанным подходом можно также сохранять навигацию при переходе между сайт коллекциями. Более того узлы навигации можно показывать и из стороннего сайта, расположенного на другом веб сервере). При этом у нас есть один подсайт (SPWeb), который является источником карты узлов навигации (другими словами на всех других сайтах мы хотим показывать такую же верхнюю навигацию, как на этом “особенном” сайте).

Как я упоминал в предыдущей части, есть определенные проблемы с реализацией cross-site навигации для сайтов публикаций. Если вы смотрели предыдущую часть, то уже знаете, что в классе SPNavigationProvider есть публичное виртуальное свойство Web:

public class SPNavigationProvider : SiteMapProvider
{
    // ...
    protected virtual SPWeb Web { get; }
}

Также как вы видите класс SPNavigationProvider не является изолированным, т.е. мы можем создать кастомный провайдер навигации, наследуя SPNavigationProvider, и переопределить в нем свойство Web например так, чтобы оно всегда возвращало наш веб сайт – источник для навигации – см. часть1. К сожалению для сайтов публикаций (pubilshing sites) этот подход не может быть использован, потому что класс провайдера навигации PortalSiteMapProvider, который там используется, не имеет виртуальных свойств аналогичных свойству Web в классе SPNavigationProvider, который используется в WSS. Если посмотреть код PortalSiteMapProvider в рефлекторе, то можно обнаружить два свойства CurrentSite и CurrentWeb, очень близкие к тем, что нужны нам:

public class PortalSiteMapProvider : SiteMapProvider
{
    // ...
    public SPSite CurrentSite { get; set; }
    public SPWeb CurrentWeb { get; set; }
    // ...
}

Хотя PortalSiteMapProvider также не является изолированным, указанные свойства не виртуальные. Поэтому простой подход с наследованием PortalSiteMapProvider и переопределением свойств здесь не подходит (стандартная функциональность Sharepoint-а, которая работает с ссылками на базовый класс PortalSiteMapProvider будет использовать его реализацию вместо нашей). Можно попробовать использовать reflection, но я не уверен, что этот подход окажется рабочим. Существуют ли другие способы решения проблемы (без наследования и рефлекшена)? Да, существуют – и я хочу рассказать об одном из таких решений (впрочем, хотя оно и обходится без трюков с рефлекшеном, простым его назвать нельзя).

Идея в том, чтобы создать кастомный провайдер навигации. В качестве базового класса можно использовать стандартный SiteMapProvider из ASP.Net. Но в нашем случае лучшим выбором будет класс StaticSiteMapProvider, в котором уже реализованы некоторые методы, так что нам останется меньше работы (напр. StaticSiteMapProvider  используется в качестве базового класса для другого стандартного провайдера XmlSiteMapProvider). В документации этого класса говорится следующее:

Класс StaticSiteMapProvider представляет частичную реализацию абстрактного класса SiteMapProvider и предоставляет два дополнительных метода: AddNode и RemoveNode, а также абстрактный BuildSiteMap и защитный Clear методы.

Класс StaticSiteMapProvider поддерживает запись поставщика карты веб-узла (например, объекта XmlSiteMapProvider), который переводит карту веб-узла, хранящуюся в постоянном хранилище, в карту, хранящуюся в памяти. Класс StaticSiteMapProvider предоставляет основные реализации для сохранения и получения объектов SiteMapNode.

При расширении класса StaticSiteMapProvider используются три наиболее важных метода: GetRootNodeCore, Initialize и BuildSiteMap. Реализация методов Clear и FindSiteMapNode задана по умолчанию, и являются достаточной для большинства пользовательских реализаций поставщиков карт веб-узелов.

Это очень близко к нашему случаю – в качестве “постоянного хранилища” для карты узлов у нас выступает веб сайт в Sharepoint (точнее content база данных, т.к. данные навигации хранятся имеено в ней в конечно счете). Остается вопрос: как выбрать карту узлов (т.е. коллекцию объектов PortalSiteMapNode) для определенного сайта публикации? Очевидный ответ – используя PortalSiteMapProvider, но вызывать его следует в контексте сайта, из которого мы хотим получить карту узлов для навигации. Мы можем сделать это с помощью веб сервиса, используя следующую схему:

image_thumb2

Также нам нужно зарегистрировать наш кастомный провайдер навигации во всех веб приложениях, где мы хотим его использовать (в web.config-е – см. часть1). Наш провайдер вызовет метод кастомного веб сервиса Navigation.asmx (сам asmx файл может располагаться например в папке 12/Templates/Layouts/Custom на файловой системе веб сервера) в контексте сайта источника узлов навигации. Напр. если у нас есть 2 сайта http://example.com/site1 и http://example.com/site2, где site1 – источник, нам нужно вызвать метод веб сервиса Navigation.asmx, используя следующий URL: http://example.com/site1/_layout/Custom/Navigation.asmx. Как результат код веб сервиса будет исполняться в контексте сайта site1, так что мы сможем использовать стандартный PortalSiteMapProvider для того чтобы получить карту узлов сайта site1 для ее отображении на сайте site2.

В этой части я описал идею. Непосредственную реализацию компонентов этой схемы я опишу в следующей части.

Реклама

Об авторе sadomovalex

Старший инженер, team lead, консультант. Работаю в стеке .Net. Последние несколько лет занимаюсь разработкой enterprise приложений под Sharepoint, чему и будет в основном посвящена тематика этого блога. Также активно использую и интересуюсь ASP.Net MVC, DDD, TDD, Agile. Активно участвую в жизни многих профессиональных сообществ, SPb .Net UG, SPb ALT.Net, rsdn, Finland SP UG и др.
Запись опубликована в рубрике Navigation, Sharepoint. Добавьте в закладки постоянную ссылку.

Один комментарий на «Cross-site навигация в Sharepoint. Часть 2»

  1. Уведомление: Cross-site навигация в Sharepoint. Часть 3 | Алексей Садомов – техблог

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s