Sergey Homyuk * Dev

Sergey Homyuk as Software Developer Blog

Структура моих SharePoint проектов

Структура моих SharePoint проектов

Структуру своего первого SharePoint проекта я строил, руководствуясь принципами и практиками, которые я выработал, будучи ASP.NET разработчиком. Модульность, слабая связанность между частями проекта, точки агрегации зависимостей – все эти принципы так же удачно ложатся в основу структуры SharePoint проекта, как и в структуру большинства проектов созданных на основании других технологий. Если для вас эта тема нова или же хотите ее освежить, то я настоятельно рекомендую вам ознакомиться с серией статей Simon Ince посвященных созданию архитектуры на базе принципов заложенных в Microsoft Web Client Software Factory. В свое время они перевернули мое представление о том, как надо структурировать проекты.

Моя типичная структура одного модуля в ASP.NET проекте с backend-ом, скажем, в виде MS SQL базы данных выглядела следующим образом:

Архитектура типичного проекта

Думаю, что никого не удивил этой картинкой. Все как обычно: Repository формируется с учетом особенности базы данных, View завязывается на модель представления предлагаемую ASP.NET-ом, ну а Services (они же BLL) опираются лишь на интерфейсы торчащие из DAL и PL и ни на что конкретное не завязываются. В случае с  ASP.NET такая архитектура, в принципе, разворачивается без особых проблем – пара-тройка сервисов-фасадов для работы с HttpContext.Current и у нас полностью развязаны руки в BLL.

Но при попытке построить архитектуру SharePoint проекта по этим же принципам возникают некоторые трудности :)

В итоге, вместо, примерно, такой структуры:

Архитектура идеального SharePoint проекта

У меня получилось вот это:

Получившаяся структура SharePoint проекта

Иными словами: все слои приложения завязываются на модель SharePoint. При этом мы, разумеется, теряем всякую гибкость и жестко привязываемся всеми слоями к сущностям SharePoint. Жуть, не правда ли? Я долго и тщетно пытался все-таки скрыть от Services тот факт, что он работает с SharePoint. Но многочисленные фасады, адаптеры, прокси и прочие паттерны, которые я пытался применять, сильно замедляли процесс разработки и, в конечном счете, настолько усложняли код, что это делало его практически нечитаемым. Сейчас я остановился на мысли, что отвязаться от сущностей SharePoint на BLL не удастся, т.к. большая часть логики определяется структурой SharePoint и выполнения большей части операций приходится оперировать именно ими, а не Domain Model объектами, как это было в решениях, построенных на более легковесных платформах.

Ну, с архитектурными принципами, вроде бы более или менее определились, теперь, давайте более подробно остановимся на внутренней структуре моего текущего SharePoint проекта. Сразу оговорюсь – проект не очень большой – всего 3-4 модуля и 2 уровня их иерархии. Поэтому некоторыми из принципов я пренебрег в угоду простоты разработки и компактности решения. Вот, что у меня получилось:

Структура Solution

Весь проект разбит на модули в соответствии с их назначением. Так, к примеру, у меня были модули для работы с поручениями, жалобами, предложениями, организациями и модуль для шаблона сайта. Такое модульное разделение позволяет жестче контролировать зависимости между сервисами, т.к. каждая зависимость выливается в reference между проектами. К тому же мы получаем возможность развертывать и отлаживать каждый модуль по отдельности.

Далее, каждый из модулей в свою очередь состоит из нескольких проектов. Рассмотрим назначение каждого из проектов на примере модуля жалоб.

Структура модуля

  • Complaints – SharePoint проект с представлениями. Здесь у нас находятся Controls, Application Pages, WebParts, EventReceivers(сами определения, но не их логика), Ribbons. Плюс здесь находятся Presenter-ы (я использую именно этот паттерн для разделения логики и представления). В процессе разработки этот модуль deploy-ится чаще всего.
  • Complaints.Lists – SharePoint проект содержащий все, что связанно с уровнем хранения: Fields, Content Types, List Definitions и Instances. Обычно, заполняем его в самом начале и далее уже не трогаем.
  • Complaints.Manager – самая обычная .NET сборка, deploy которой выполняется через обычное копирование в GAC (включена в пакет всех проектов, которые ее используют). По сути, это наша рабочая лошадка. Здесь находятся репозитории для работы со списками, сервисы с бизнес логикой, утилиты и всякие вспомогательные сущности.
  • Complaints.Workflow – Ещё один SharePoint проект с рабочими процессами.

С назначением проектов в модуле вроде бы разобрались. Теперь перейдем к внутреннему строению каждого из модулей.

Common

Common

В основе решения лежат 4 сборки с общими компонентами:

  • Common.References – пустой проект, который разворачивает все сторонние сборки в GAC.
  • Common.UI – проект с общими страницами и эл-тами управления (№ custom страница с сообщением об ошибке).
  • Framework – проект с различными вспомогательными утилитами и базовыми классами, которые не относятся к предметной области.
  • GlobalResources – ну, думаю, это из названия понятно.

Complaints

Complaints

В принципе, тут все должно быть понятно из скриншота. Все четко и по полочкам. В Pages лежат строковые константы с путями и аргументами страниц использующихся внутри модуля. В Views – реализации паттерна MVP.

 

Complaints.Lists

Complaints.Lists

Все сгруппировано по спискам. Там где есть необходимость – определены Custom формы. Они также построены с использованием паттерна MVP. Field-ы лежат в корне проекта.

Complaints.Manager

Complaints.Manager

Пожалуй, самый интересный и сложный по своей структуре модуль.

  • В Entities лежат различные вспомогательные DTO, которые, как правило, формируются в сервисах и передаются во View.
  • Handlers – это своеобразные Presenter-ы для EventReceiver-ов. Они определяют какие сервисы и в каком порядке вызывать для обработки того или иного события.
  • С Helpers, Resources и Services, думаю все понятно.
  • Для каждого из списков имеется свой Repository, в который включены следующие файлы:
    • Entity – небольшой и абсолютно «плоский» DTO, который формируется вручную из SPListItem. Используется там, где-то нужно просто получить и отобразить.
    • Fields – набор строковых констант-имен полей.
    • ListDefinition – сущность, отображающая сам список. Содержит ряд вспомогательных методов для работы с  ним (но не с его элементами).
    • Repository – а это, непосредственно, сам репозиторий с CRUD методами для работы с элементами списка. Он абсолютно stateless, все, что нужно – приходит к нему в аргументах методов.

Модуль может зависеть только от других Manager-ов. Но это крайне нежелательно. В идеале – он автономен и зависит лишь от утилитарных сборок, вроде GlobalResources и Framework.

Complaint.Workflow

Complaints.Workflow

Тут ничего особенного. Просто определения рабочих процессов, из которых дергаются необходимые сервисы, определенные в ComplaintsManager.

Вот, что у нас в итоге получается в плане зависимостей между проектами модулями:

Зависимости между проектами модуля

А вот схема зависимостей между модулями:

Зависимости между модулями

Архитектура не идеальная, но вполне жизнеспособная и расширяемая. При дальнейшем росте проекта и увеличении степени зацепления между модулями имеет смысл выделить интерфейсы сервисов и сущностей в отдельную сборку. Но тут надо быть аккуратным и не плодить сильно много SharePoint проектов – иначе замучаетесь ждать пока выполнится их deploy. Тему архитектуры проектов в SharePoint можно развивать и дальше, но, пожалуй, оставлю это на следующую статью. А сейчас жду ваших комментариев и предложений!

3 ответов на Структура моих SharePoint проектов

  1. akornev Июль 8, 2011 в 06:45

    Очень полезная статья. Спасибо.
    Если возможно, было бы интересно узнать про реализации паттерна MVP на примере.
    Что содержится в Search.aspx, ISearchView.cs, SearchPresenter.cs?

  2. Sergey Homyuk Июль 8, 2011 в 07:21

    akornev, пример с Search не очень нагляден, т.ч. давайте я приведу пример эл-та управления для работы с рейтингом реализованным с использованием паттерна MVP.

    Вот, непосредственно, код: http://codepaste.net/pm164d (на небольшие опечатки не обращайте внимание, вырезал мусор).

    Думаю, все должно быть более или менее понятно:
    View знает о Presenter и при необходимости дергает его методы, передавая туда весь нужный контекст.
    Presenter ничего не знает о конкретных View и оперирует лишь интерфейсом IView, через которое получает доступ к его свойствам и, возможно, методам (но это реже).

    Если что, хорошая статья про паттерн MVP есть на rsdn: http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml

  3. Sergey Homyuk Июль 8, 2011 в 07:24

    + Советую обратить внимание на мою беседу с Андреем Макеевым на тему рациональности использования MVP в SharePoint: https://plus.google.com/111626777246307386943/posts/WC2DQ9mwnaL

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

Fill in your details below or click an icon to log in:

Логотип WordPress.com

You are commenting using your WordPress.com account. Log Out / Изменить )

Фотография Twitter

You are commenting using your Twitter account. Log Out / Изменить )

Фотография Facebook

You are commenting using your Facebook account. Log Out / Изменить )

Connecting to %s

Follow

Get every new post delivered to your Inbox.