пятница, 20 мая 2011 г.

Веб-сервис, который работает с SharePoint


Иногда хочется чего-то необычного...

Нужно было из базы данных импортировать данные в список SharePoint. Сделать-то плёвое дело: сопоставление поля из БД и поля из SQL сделал и импортируй на здоровье. Но было ограничение - импортировать данные, как только их изменили в БД. Это значительно повышало замороченность задачки. Особенно учитывая, что импорт БД -> SharePoint 1000 записей и 12 полей проходил за 50-60 секунд.

Отвлечение: Почему не использовать BDC (который сейчас BCS) Потому что это зло =) Ни рабочий процесс прикрутить, ни связять с другим списком.

Мой извращённый ум, который теперь занимается унификацией архитектуры решений в госсекторе (проще говоря, старается во всём выделять универсальные компоненты и развивать их) придумал гениальную идею, которая стоила многих нервных клеток =) 

Есть определённые точки входа из которых изменяют данные в бд
Есть сама БД
Есть список SharePoint

ИДЕЯ: все точки входа (или сама база данных) при изменении данных вызывают веб-сервис, который начинает загрузку данных в SharePoint, а попутно ещё и статус загрузки показывает.

Реализация стандартная:
у веб-сервиса два метода. Первый запускает загрузку данных в отдельном потоке и возвращает идентификатор, по которому через второй метод можно получить состояние загрузки (просто в кеше сервера лежит и обновляется потоком что-то типа "идентификатор -> состояние").

Ну и как всегда всё упёрлось в SharePoint, уж не знаю при делах ли тут конкретная версия, но у меня был 2007.

Проблема первая: веб сервис не видит веб-сайт, т.е. когда делаем new SPSite выпадает 404 ошибка. Ну тут ошибка ожидаема была, просто не 404, а скорее что-то типа 401-403 (ошибка авторизации). Как ни странно, но именно в авторизации и была проблема. Решается легко: либо нормально настраиваем безопасность в IIS у веб-сервиса (передача данных пользователя), либо делаем веб-сервису олицетворение учёткой, которая имеет права на портале, либо запускаем веб-сервис в том же пуле приложений, что и у портала.

Проблема вторая: отняла много сил в первую очередь из-за неопытности в такого рода разработке. Зато многому начился ;) При SPListItem.Update вылетает ошибка, мол некорректные данные или их кто-то в другом месте изменил. Первое, самое стандартное решение - SPSecurity.RunWithElevatedPrivileges(() =>{...}) не прокатило, как ни странно. Второе, третье и двадцать четвёртое тоже. А вот двадцать пятое прокатило, вот и пишу, чтоб не забыть.
На деле оказывается решается вопрос очень просто, все процедуры по работе со списком стоит начинать с web.AllowUnsafeUpdates = true, ну и заканчивать с web.AllowUnsafeUpdates = false. Т.е. оказывается изменение данных в списке таким образом является не безопасным. Как-то додуматься почему так -  не смог, но методом перебора нашёл.

Ну собственно и всё. Разве ещё чуть разглагольствований о самой схеме загрузки.
Чем удобен такой подход с веб-сервисом? Удобно тем, что долговыполняющие операции мы делаем не в веб-странице/веб-части, а в отдельном сервисе. При переходе со страницы на страницу мы не потеряем данных о потоке, всегда его можем опросить на предмет состояния. Ну и конечно универсальность - в передаваемых аргументах методу импорта мы указываем привязки между базой данных и списком, этот веб-сервис можно использовать с любым списком (лишь бы привязки были). Чтобы можно было использовать ещё и с любой базой данных, нужно всего лишь использовать DbProviderFactory, ничего сложного в этом нет, разве что лишаемся пары удобных методов из классов подключения к базе данных SQL server.

А ещё можно этот веб-сервис поместить к веб-сервисам SharePoint, ну чтоб в одной куче лежал. По простому и по некорректному это делается просто: перекидываем файлы веб-сервиса в директории SharePoint на диске C:/Program files/....ну и как обычно. По правильному - это сгенерить кучку файлов .disco и .wsdl чтобы наш сервис был "discoverable by listing it in Spdisco.aspx" и имел "Web Services Description Language". Но тут чёрт ногу сломит...

Комментариев нет: