четверг, 13 ноября 2014 г.
SharePoint 2013 Workflow: HttpSend и DynamicValue
четверг, 26 декабря 2013 г.
Работаем с внешними данными в Workflow с помощью WCF Data Services и OData
Если нужно каким-то образом обращаться к внешним данным из рабочего процесса, то самым логичным решением видится разработка специального сервиса, который бы взял бы на себя работу с данными.
Разработка такого сервиса не вызывает проблем, если использовать технологию WCF Data Services.
Очень удобно использовать службы данных WCF с технологией Entity Framework: добавляем модель и создаём службу на её базе:
Надо сказать, что тут есть ограничение: службы данных работают исключительно со стандартными типами данных. Например, у меня в таблице БД есть колонка типа geography. Entity Framework создал мне сущность с полем типа GeographyPoint. Но вот службы данных работать с ним отказались. Пришлось делать отдельную мини-модель без этой сущности, благо работать с ней не нужно было. Может есть ещё какие-то ограничения, пока отдельно этот вопрос не исследовал, если кто-то сталкивался, пишите, пожалуйста, в комментариях.
Итак, служба данных у нас готова. (Всего-то максимум час работы, красота!) Службы данных работают через OData. Это для нас очень удобно, так как позволяют легко вызывать их из рабочего процесса с помощью активности HttpSend(я уже упоминал про работу с HttpSend тут). Для каждого действия с внешними данными (получение или обновление) я создал отдельную активность рабочего процесса.
Трудности могут вызвать формат строки URI для запроса к сервису. Но на помощь приходит документация. Например, тут описание запроса данных с фильтрацией. А здесь описание обновления отдельного свойства.
Отдельно хочу сказать про операции обновления. Выполняются они с помощью операции PUT. В IIS эта операция требует специальных разрешений на папку, в которой находится сервис. Workflow Manager делает запрос из-под своего аккаунта. Поэтому ему необходимо дать разрешения:
Адрес службы данных рабочий процесс должен откуда-то получить. Я передавал адрес в виде строки как параметр при запуске рабочего процесса. Для этого пришлось отказаться от автоматического запуска рабочего процесса и запускать его в обработчике событий SharePoint. Как это делать я уже описывал.
Про самое главное здесь - про безопасность. Как это всё друг с дружкой увязывается.
Служба данных работает из-под своей учётной записи. Я так и назвал её - DataService. Из-под этой учётной записи будет идти обращение к БД. В настройках IIS должна быть выключена анонимная аутентификация и включена аутентификация Windows для операций обновления. Если операций обновления нет, то в принципе можно оставить анонимность, но я бы всё равно не стал бы так делать.
Безопасность на уровне БД определяется путём заведения специальной роли, я её назвал Data Service. Выдал ей разрешения на нужные объекты БД, и добавил в неё учётную запись DataService.
Workflow Manager работает также под своей учётной записью - sp_workflowmanager. Ей нужны разрешения на папку IIS (см. выше).
HttpSend по-умолчанию посылает HTTP-запрос анонимно, без указания заголовка аутентификации. Для того, чтобы его заставить всё-таки отсылать заголовок, нужно указать пустой заголовок Authorization:
Вот и всё. Надеюсь, кому-нибудь пригодиться.
четверг, 5 декабря 2013 г.
SharePoint 2013 Workflow: ошибка в CreateListItem: System.FormatException: Hexadecimal 0x expected in '{0}'.
Продолжаю тему рабочих процессов в SharePoint 2013. Столкнулся со странным: казалось бы, совершенно невинное activity CreateListItem выдает странное исключение: System.FormatException: Hexadecimal 0x expected in '{0}'. Покопавшись в блогах и форумах, быстро нашёл причину: ошибка происходит при выборе имени списка из выпадающего списка в свойстве ListId:
Visual Studio подставляет в свойство автоматически выражение типа: System.Guid.Parse("{$ListId:Lists/List1;}"). А среда, видимо, выражение "{$ListId:Lists/List1;}" вычисляет некорректно. В результате, ошибка при разборе Guid.
В интернетах советуют просто захардкодить в свойство ListId идентификатор (guid) списка. Но такое решение мне не показалось хорошим. Нужно было придумать, как получить идентификатор списка в процессе выполнения. Странно, но среди стандартных activity нужное действие по получению свойств произвольного списка отсутствует.
На выручку пришло событие HttpSend и REST (про REST смотри, например, тут: Working with lists and list items with REST). С помощью HttpSend посылаем запрос вида: webUrl + "/_api/web/lists/GetByTitle('" + ListTitle + "')", в ответ получаем все основные свойства списка. Для удобства результат лучше получать в виде JSON. Для этого посылаем специальный HTTP-заголовок: Accept=application/json;odata=verbose
Для удобства все эти действия оформил в виде custom activity. Результат получился примерно такой:
В результате, сначала получаем ИД списка с помощью нашей activity, сохраняем в переменной и указываем её в параметре ListId:
вторник, 3 декабря 2013 г.
SharePoint 2013 Workflow. Ошибка присоединения рабочего процесса к списку
Недавно столкнулся со следующей проблемой. При очередном разворачивании решения рабочий процесс не ассоциируется со списком. Переактивация фичи с рабочим процессом проблему не решило. Анализ логов ничего не дал, ошибок вовсе нет. Как всегда в таких случаях, пришлось копать внутренности SharePoint.
Начал с анализа feature receiver для workflow (Microsoft.SharePoint.WorkflowServices.SPWorkflowPackageFeatureReceiver, код сгенерирован с помощью ILSpy):
Как видно, обработчик почти ничего не делает, только проверяет корректность файлов в модуле. Значит, ошибка кроется не здесь.
Стал смотреть, что вообще у нас есть в фиче. Один модуль, который разворачивается по хитрому URL, вроде такого: wfsvc/da43c771febd4e3ab4c888a854d1a17d. В модуле файл XAML с рабочим процессом и фейковый файл вроде WorkflowStartAssociation. Открыв SharePoint Designer 2013 пути wfsvc не нашел. Тогда как всегда помогла замечательная утилита SharePoint Manager. В дереве ищем сайт, раскрываем там RootFolder, и - вуаля! Вот наши модули рабочих процессов:
Удаляем застрявший модуль, переактивируем фичу, и рабочий процесс прикрепился к списку.
SharePoint 2013 Workflow. Запуск рабочего процесса из серверного кода.
В стандартном шаблоне Visual Studio присутствует простой code snippet на Javascript для запуска рабочего процесса с клиента. На основе него написал вот такой простой код, запускающий рабочий процесс на стороне сервера. Таким образом удобно запускать рабочий процесс в обработчике событий для особых типов содержимого:
WORKFLOW_ID можно найти в свойствах рабочего процесса как WSGUID, открыв файл Elements.xml: