четверг, 1 сентября 2011 г.

Чем плох CAML в SharePoint?

В последнее время, я всё чаще и чаще пишу обертки для CAML. Началось всё, кстати, с моего любимого SharePoint 2010 Fluent Ribbon API, благодаря которому я очень глубоко изучил Ribbon. Кстати, ведь забыл в блог написать, всего пару дней назад, зарелизил версию 1.3! :)

Создание кнопки на ленте с помощью Fluent Ribbon 


Дак вот, после Fluent Ribbon, на работе закодил Fluent List API, для программного создания списков. Идея примерно такая же: создаем ListDefinition, в нем - FieldDefinition'ы, потом есть ListController, ему в метод Create передаем описание списка и объект SPWeb - вуаля, список создан. Плюс там еще куча вкусных фишек, можно и представления создавать, и на заданные WebPart-страницы сразу же их выкладывать, и локализация поддерживается... В общем, пользуюсь с огромным удовольствием!

Потом была еще обертка для SharePoint Batch List API, для пакетной обработки списков. Делал для рабочих нужд, не очень универсально. Если доделаю - обязательно выложу в паблик.

Наконец, в последние дни усиленно кодю новый проект, SharePoint EcmaScript CAML Builder, предназначенный для работы с CAML запросами к спискам на стороне клиента. По задумке - это аналог знаменитого Camlex, но по синтаксису отличается: на JavaScript всё-таки нет возможности анализировать лямбда-выражения. Да и самих лямбда выражений, впрочем, там тоже нет :-)

Создание CAML-запросов с помощью CamlJS

К слову, Camlex в серверном коде я всегда стараюсь использовать. Читабельность повышается неимоверно, и вероятность ошибки ниже. Конечно, проект не идеален: хотелось бы больше compile-time validation, но хотя бы runtime сообщения об ошибках очень внятные - уже здорово :) В общем, рекомендую!

Подводя итог, тенденция видна невооруженным взглядом. Весь CAML - нуждается в обертывании (а это, по сути дела, весь SharePoint'овский служебный XML). Но почему? Давайте разбираться.

Чтобы понять, в чем проблема, нужно заглянуть внутрь SharePoint. Если вы когда-нибудь это делали, то должны знать: центральный объект всего SharePoint'а - это некий SPRequest. Именно через этот класс в конце концов проходит, ну как минимум, вся работа с данными. А если взглянуть в этот класс, то, о ужас, обнаруживается, что это не более чем wrapper Unmanaged кода!!
Связь с мифическим ядром :)

Да-да, оказывается, когда-то SharePoint был полностью Unmanaged проектом, и это ядро осталось с тех самых времен.

Ага, теперь-то понятно, откуда берутся все эти печально известные ошибки вида "Cannot complete this action. Please try again" :)

И если проследить путь CAML-кусков, которые мы переправляем SharePoint'у, то вы очень скоро обнаружите, что все эти XMLSchema в конечном счете передаются именно в SPRequest. Иными словами, вся обработка XML осуществляется в неуправляемом коде.

И вот в том самом мифическом ядре SharePoint'а, складывается впечатление, что существует несколько самописных XML-парзеров или препарсеров, чрезвычайно нежных и чувствительных к передаваемому им XML. По крайней мере, я ни разу не видел таких ошибок при использовании любого современного известного парсера...

Вот вам несколько ошибок XML-парзинга для примера:
То есть, получается, что базовые возможности XML не всегда поддерживаются. С другой стороны, говорят, парзер спокойно глотает некоторые не well-formed XML-строки (что еще больший нонсенс).

Итак, получаем следующее: XML-парзер явно кривоват. Но весь SharePoint завязан на CAML, без него не обойтись. Что делать? Решение естественное: генерировать код, который уж точно работает, и в котором никто не сможет уже поставить комментарий <!-- Здесь был Вася -->, и сломать всё :) Генерация позволит избежать повторяющихся ошибок, к тому же уничтожит вероятность опечаток, улучшит документированность и структурированность кода, ну и всё такое в общем :)

Мораль: используете сложный CAML-код - пишите программную обертку.

12 комментариев:

  1. Можно ли где-нибудь скачать ваш проект Fluent List API?

    ОтветитьУдалить
  2. Нет, это рабочий проект, он создавался по большей части в рабочее время, к тому же заточен под использование в конкретном проекте.

    ОтветитьУдалить
  3. А зачем писать свою обертку поверх CAML, если она уже есть под названием LinqToSharePoint?

    ОтветитьУдалить
  4. Eugene, ну во-первых, CAML это не только CAML Query. CAML Query это лишь малая часть CAML.
    Создание списков, их определений, представлений, страниц, заполнение страниц, плюс все эти Custom Actions - да собственно весь вот этот настроечный XML, который есть в SharePoint (всё что мы пишем в Elements.xml, schema.xml, onet.xml), это всё и есть CAML.

    Что касается Linq-To-SharePoint, к сожалению первая реализация этого функционала очень далека от идеала. Печально известная "проблема первой версии", надо полагать. В общем, для серьезных задач использовать Linq-To-SharePoint довольно сложно, лично мне ничего путного с ним добиться не удалось, хотя много в этом направлении копал, и даже например использовал плагинную реализацию Model-First для Linq-To-SharePoint - это уже удобнее чем SPMetal, но вообще все сейчас идут к Code-First, и я надеюсь что в SharePoint ребята придут туда же.

    В общем, на мой взгляд, Linq-To-SharePoint еще пока не готов для серьезных проектов.

    ОтветитьУдалить
  5. Я имел ввиду CAML запросы на обработку данных и Работу со списками как с типизированными коллекциями. Какие там серьёзные задачи неудаётся сделать не понятно. Файлы которые генерит SPMetal - да, приходится править ручками что бы нормально потом работать с классами.

    ОтветитьУдалить
  6. Про CAML Query:
    Что касается неудобства применения LinqToSP для работы с данными списков/библиотек не убедительно. Подводных камней там уйма. Приведи хоть один реальный пример.

    Про CAML Definitions:
    Чтобы завернуть CAML декларации в код, надо много писать кода, а времени на это на проектах никогда нет. CAML конечно плох, но его не обойти никак. Если за пример брать твой FluentRibbon то мне очень нравится решение. Но вот для FluentListAPI я не могу придумать сценариев применения.

    Про статью:
    Ты пишешь, что надо писать обертки, потому что CAML обрабатывается неуправляемым кодом.
    Теперь берем FluentListAPI и проследим метод AddFieldToList() класса ListController. Он все равно вызывает стандартные методы шарика, которые в свою очередь формируют CAML и отправляют его в SPRequest.
    За что боролись, на то и напоролись.

    ОтветитьУдалить
  7. Zhukov, в статье как раз и написано что без CAML не обойтись. Обертывание нужно, чтобы не давать девелоперам напрямую работать с CAML, чтобы минимизировать число гейзенбагов, и всяких нелепых ошибок/опечаток.

    ОтветитьУдалить
  8. Если взять такой сценарию:
    есть SiteDefinition, который содержит в себе ContentType, ListTemplate и ListInstance.
    Ты считаешь, что все это содержимое должно быть описано в коде и деплой должен происходить в EventReceiver'е?
    Мысль конечно интересная. А были у тебя проекты, где ты (или не ты) успешно это применял?

    ОтветитьУдалить
  9. Zhukov, угу, проект называется DeskWork.ru :) Используем очень активно по всему проекту. От развертывания через CAML вообще сознательно отказались, из-за проблем с обновлениями - выделили время и переделали. Раньше было всё на CAML, сейчас всё развертывается только программно.

    ОтветитьУдалить
  10. Получается что каждый работает со своим такие фреймворком, TOPSbi со своим,Terralink со своим CAML генератором Softline тоже частично со своим и каждый свой фреймфорк хвалит))

    ОтветитьУдалить
  11. Eugene, мне кажется наличие программных оберток и альтернативных CAML-решений как раз и обусловлено неудобством использования нативного SharePoint'овского API в имеющемся виде, и отсутствием хороших бесплатных решений для этой проблемы.

    Написание оберток для SharePoint'а и наверное для любой другой платформы - это неизбежно и совершенно логично. Всегда найдется какое-нибудь неудобство, которое стоит сделать удобным и сэкономить тем самым много времени и сил. SharePoint - очень широкая и многообразная платформа, что-то там сделано хорошо, но далеко не все.

    P.S. Что касается Softline, хотя я там на текущий момент работаю (а кроме меня - еще 1700 человек), в данном блоге я представляю самого себя. Прошу не отождествлять :)

    ОтветитьУдалить
  12. Andrey Markeev, насчет обертки для CAML, полностью с тобой согласен, сам на второй месяц знакомства с SharePoint, написал обертку (этакий CAMLutility) и таскаю его из проекта в проект, оптимизируя и "долизывая" ))

    ОтветитьУдалить

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