среда, 24 октября 2012 г.

Вызов веб-сервиса без кода: DataFormWebPart!

No-code решения – очень полезны и нужны. Часто их использовать проще и правильнее, чем писать серверный код. А иногда, без них просто не обойтись: например, если портал хостится в облаке и нужно пройти 10 инстанций и ревью, чтобы что-то серьезное туда задеплоить. Я лично столкнулся с такой ситуацией на работе, в связи с чем и родился этот пост.
В общем-то, скажете вы, веб-сервис дернуть ведь проблемы нет, берешь jQuery (или например уже заточенные под это SPServices) и дергаешь… К сожалению, не всегда всё так просто. Например, что если веб-сервис требует авторизацию (а пароли на клиенте хранить ну уж никак нельзя, согласитесь), или же доступ к веб-сервису ограничен и он доступен только для определенных IP-адресов (т.е. принципиально возможен только server-side вызов). А бывает и так, что даже стандартные веб-сервисы SharePoint из _vti_bin недоступны извне (их часто блокируют). Что делать в этом случае?

Варианты решения

Как всегда в SharePoint, решений может быть несколько. Как минимум, три:
  1. BCS – это наипервейший инструмент для работы с любыми внешними данными в SharePoint, будь то веб-сервисы или базы данных. Этот вариант предлагает на самом деле очень большие плюсы: например, если подцепить данные из некоего веб-сервиса через BCS, то по ним можно будет настроить поиск, или же надежно запретить доступ к той или иной сущности для конкретных пользователей/групп, и т.д. Также, BCS поддерживает разные варианты аутентификации, что тоже очень важно – иногда без этого просто никак.
  2. В некоторых случаях можно проделать вызов сервиса через Workflow. Особенно привлекательно этот вариант выглядит для использования в SharePoint 2013, т.к. там в SPD Workflow уже даже есть такой Action, Call webservice. На MSDN можно даже скачать пример такого Workfow.
  3. Наконец, можно использовать имеющуюся в SharePoint стандартную веб-часть DataFormWebPart, в сочетании с SoapDataSource. Пожалуй, основная проблема с этим подходом – это то, что SoapDataSource не умеет делать Claims аутентификацию к веб-сервису, т.е. к примеру это не будет работать в Office365 для обращения к OOTB веб-сервисам SharePoint (например, к UserProfileService).
BCS – повторюсь, способ практически идеальный, но требует наличия довольно серьезных привилегий (администратор фермы, администратор тенанта или администратор service application), поэтому этот вариант в нашем случае был отклонен, ибо он потребовал бы работу “через третьи руки”, а третьи руки, как известно, работать редко когда хотят :) Но в случае если у вас задача дернуть веб-сервис стоит например для Office365, то рекомендую именно этот подход использовать.
Что касается Workflow, к сожалению, в SP2010 Workflow действия “вызов веб-сервиса” пока еще нет... Пришлось бы его писать и деплоить – а деплоить любой код, даже очень простой – в нашем случае было долго.
Ну и соответственно, остался последний вариант, самый “легковесный” и быстрый, DataFormWebPart + SoapDataSource, благо у нас используется Windows аутентификация.

Про DataFormWebPart

За последние полгода, я сделал уже несколько довольно серьезных решений на основе DataFormWebPart (далее DFWP). Веб-часть конечно устарела по сравнению с XsltListViewWebPart – и стили старые, и некоторые стандартные штуки не поддерживаются (например группировка с ajax-подгрузкой данных). Но с другой стороны, часть задач решается именно с использованием DFWP, благодаря тому, что к ней можно подцепить практически любые данные.
Для этой веб-части довольно легко написать custom datasource, да и стандартные SharePoint’овские источники данных очень гибкие и для большинства задач подходят. Смотрите сами:
  1. SPDataSource – получает данные из списков,
  2. XmlDataSource – из xml-файлов.
  3. SoapDataSource – вытаскивает данные из веб-сервиса.
  4. LinkedDataSource – этот источник позволяет объединить несколько источников данных из пп. 1-3, т.о. например показав в нашей веб-части саггрегированные данные сразу из двух списков, или из двух списков и веб-сервиса, и т.д.
Визуальные средства SPD позволяют быстро нагенерить для этой веб-части нужный XSLT, например отображающий данные с группировкой, пейджингом и т.д. В результате получаются быстрые в исполнении, и при этом гибко настраиваемые решения, т.е. в случае косметических правок или простых кастомизаций под конкретного клиента достаточно просто поправить XSLT, и вуаля, готово. А поскольку DFWP всегда лежит на странице типа Site Page, которую можно в любой момент откатить к определению сайта, то получаем одновременно и некоторую степень надежности :)
В общем, если вы с DFWP еще не работаете – рекомендую, можно брать на вооружение.

Создаем SoapDataSource

Итак, как же всё-таки веб-сервис то вызвать из DFWP?
Для начала, нужно создать источник данных. Открываем SPD, наш сайт, вкладку “Data sources”. Видим длинный список всяких уже имеющихся источников (в основном это просто списки и библиотеки узла), и сверху видим ribbon со следующими кнопками:
image
Обратите внимание, все типы источников данных, которые я выше перечислял, тут как раз присутствуют.
Т.е. чтобы создать SoapDataSource, очевидно тыкаем SOAP Service Connection.
В качестве примера сегодня я буду рассматривать получение данных из профиля текущего пользователя (кстати, часть этих данных можно взять из UserInfoList, но не все). Т.е. буду коннектиться к http://(адрес портала)/_vti_bin/UserProfileService.asmx, и вызывать метод GetUserProfileByName. В вашем случае это может быть любой другой веб-сервис и любой его метод.
datasource
Здесь обратите внимание на три вещи:
  1. Всем динамическим параметрам этого метода (т.е. которые будут меняться в зависимости от текущего пользователя, параметров командной строки и т.д.) нужно выставить галочку “The value of this parameter can be set via a webpart connection”:
  2. Здесь же, обязательно укажите валидные дефолтовые параметры для DataSource! Их можно будет потом убрать, но они нужны для того чтобы SPD мог сгенерировать разметку DFWP.
  3. Если вам нужно настроить аутентификацию, перейдите на вкладку Login, и выберите один из способов: Windows, Basic или через Secure Store.
В общем, всё настроив, жмем ОК, и видим что в список источников данных добавился наш:
image

Создание DFWP

Пока что всё очень просто, не так ли? И дальше – тоже просто, но есть нюансы :)
Переключаемся в All files, и создаем aspx-страницу (через ribbon). Можно создать как простую aspx-страницу, так и например WebPart-страницу, в зависимости от ваших нужд.
Далее, добавляем на эту страницу Data view, указывающий на наш датасурс (опять же через риббон, вкладка Insert). В результате получаем примерно такую картинку в дизайнере:
dataretrieved
Вот это то что вы увидите – это на самом деле очень круто, особенно с учетом того, что если вы посмотрите во вкладку Code, то там сгенерен XSLT код и по сути дела, вам только останется его немножко подправить. А можно сделать это даже визуально, если вам эти данные нужно просто отобразить. Но я вот использовал запрос к UserProfileService чтобы выяснить тип сотрудника, и в зависимости от типа сотрудника, вывести или не вывести несколько ссылок.
Кстати, к большому сожалению, Design View в SharePoint Designer и соответственно генерация XSLT тоже - больше не поддерживаются в SharePoint 2013.

Передаем параметры

Итак, в представленном выше случае мы получили данные профиля пользователя по его AccountName, используя некоторое захардкоженное DefaultValue для параметра AccountName. Осталось маленькая деталь – это AccountName расхардкодить :)
Логично предположить, что AccountName будет передаваться либо через строку запроса, либо вообще должен соответствовать текущему пользователю.
На помощь здесь придет очень мощная SharePoint’овская штука, называемая ParameterBindings. Про ParameterBindings очень хорошо написано у Stefan Stanev, и я честно говоря думал, что более полно не напишешь и что он все нюансы осветил. Но нет, оказывается для DataFormWebPart привязка к WPVariable не работает, и единственный оставшийся способ получить логин текущего пользователя – это использовать привязку ServerVariable(LOGON_USER). Ну а из строки запроса вытащить любое значение очень легко с помощью привязки QueryString.
Кстати, ParameterBindings тоже можно добавлять визуально в SPD, хоть и не все типы.
Переключаемся в Design View. Кликаем на DataFormWebPart, и затем в риббоне – Parameters.
Там уже есть параметр AccountName, но у него указан тип None. Если переключить этот тип на QueryString, указать название параметра адресной строки (пусть будет тот же самый AccountName), и удалить значение по умолчанию:
, то перейдя на страницу (Ribbon –> Preview in browser), и добавив к адресу страницы “?AccountName=ваш_логин”, собственно получим что параметр берется из адресной строки.
Чтобы DFWP запрашивал данные текущего пользователя, нужно перейти во вкладку Code, найти строку
<ParameterBinding Name="AccountName" Location="QueryString(AccountName)" DefaultValue=""/>

И заменить значение атрибута Location на ServerVariable(LOGON_USER).

Заключение


Давайте вкратце подведем итоги:


  1. Для вызова WebService лучше всего использовать BCS, но иногда подойдет и DataFormWebPart. А в SharePoint 2013 есть еще один потенциальный вариант – SPD workflow.
  2. DataFormWebPart требует совершенно минимальные права для развертывания, он создается за пару минут, его легко и быстро можно оттестировать, в том числе на Production environment (кстати для тестирования не обязательно даже иметь Contribute права на основной сайт, можно разместить DFWP на своем личном узле).
  3. DataFormWebPart не сможет вызвать веб-сервис, если он расположен на сайте с Claims-аутентификацией. Внимание! Поскольку новый SP2013 поддерживает только Claims-аутентификацию, обращаться к внутренним веб-сервисам так там не получится, т.е. пример с UserProfileService в SP2013 не будет работать! Но для веб-сервисов которые хостятся вне шарепойнта, этот вариант по-прежнему вполне подходит.
  4. У DataFormWebPart есть ParameterBindings, которые позволяют передавать в качестве параметров в веб-сервис некоторые стандартные значения сессии, например логин текущего пользователя.

За сим, у меня пока всё, так что удачи!

4 комментария:

  1. "Кстати, к большому сожалению, Design View в SharePoint Designer и соответственно генерация XSLT тоже - больше не поддерживаются в SharePoint 2013."

    Как так?? А зачем же теперь нужен будет этот самый Designer, если там нельзя будет генерировать XSLT???

    ОтветитьУдалить
    Ответы
    1. Всё то же самое, тока без Design View. Т.е. код пишем ручками.
      Ну а так, там еще есть всякие External Content Types, Workflow, и т.п.

      Удалить
    2. Это же ужасно! Когда DFPW добавляешь на страницу и настраиваешь группировку, сортировку и т.д., там километры когда генерируются... :(

      Удалить
    3. Согласен, а чо сделаешь?! Разве что писать собственный opensource аналог SPD :)

      Удалить

Внимание! Реклама и прочий спам будут беспощадно удаляться.