Visual Studio 2012

Формируйте данные с помощью Visual Studio LightSwitch 2012

Ян ван дер Хаген

В этой статье обсуждается предварительная версия Visual Studio LightSwitch 2012. Любая изложенная здесь информация может быть изменена.

Продукты и технологии:
Visual Studio LightSwitch 2012
В статье рассматриваются:

  • проектирование данных;
  • формирование данных (shaping data);
  • предоставление доступа к данным;
  • создание клиентских приложений.

Первый выпуск Visual Studio LightSwitch состоялся в середине 2011 г., и использование этого продукта — самый простой способ создавать бизнес-приложения для настольных компьютеров или для облака. Хотя этот продукт вскоре взяли на вооружение многие люди, имеющие отношение к IT-индустрии, некоторые профессиональные разработчики быстро пришли к выводу, что LightSwitch может оказаться не готовым для корпоративного мира. Сейчас технология быстрой разработки приложений — отличный способ создания новых и небольших приложений, но, к сожалению, история доказывает, что эти быстро созданные приложения плохо масштабируются, требуют массы усилий для взаимодействия с существующими устаревшими системами, не слишком хорошо адаптируются к быстрым изменениям в технологиях и не способны справиться с такими корпоративными требованиями, как поддержка мультитенантных систем или множества одновременных обращений пользователей. Вдобавок к этому в мире открытых стандартов, например RESTful-сервисов и HTML-клиентов, внедренных почти во всех крупных IT-организациях, кому захочется замыкаться в любом закрытом формате?

В связи с предстоящим выпуском LightSwitch 2012 я подумал, что сейчас самое время убедить некоторых друзей (профессиональных разработчиков и архитекторов ПО) отбросить свои предубеждения и (заново) оценить, насколько LightSwitch удовлетворяет современным требованиям.

И каков же результат? Оказалось, что LightSwitch 2012 не просто удовлетворяет всем этим требованиям — он намного превосходит их.

Обзор Visual Studio LightSwitch

LightSwitch дополнение для Visual Studio 2012 на основе дизайнера, которое помогает в работе с сервисами и приложениями, ориентированными на данные. Visual Studio IDE при работе с проектом LightSwitch превращается в среду разработки всего с тремя основными редакторами (в так называемом логическом режиме [Logical mode]): Entity Designer, Query Designer и Screen Designer. Эти редакторы в основном предназначены для быстрого получения результатов за счет интуитивно понятного интерфейса и простоты в использовании. Это дает некоторые очевидные преимущества разработчику, применяющему LightSwitch.

  • Во-первых, LightSwitch абстрагирует инфраструктуру (стереотипный код, который обычно приходится писать при разработке информационных систем). Простые в использовании редакторы ускоряют разработку, а значит, разработчики трудятся продуктивнее, что в свою очередь идет на пользу бизнесу.
  • Во-вторых (и, возможно, самое главное), люди, далекие от технологий, — от функциональных аналитиков и владельцев малых предприятий до «разработчиков» под Microsoft Access или Microsoft Excel (их еще часто называют народными разработчиками), которые знают свое дело от и до, — могут включиться в разработку приложения или даже самостоятельно создать его. Редакторы избавляют от выбора технологий тех, кто предпочитает избегать их, и автоматически помогают проектировщику приложения применять передовые методики, например инкапсуляцию логики предметной области в повторно используемых моделях предметной области, сохранение отзывчивости UI за счет выполнения прикладной логики в потоке, отдельном от UI-потока, или применением в клиентах шаблона разработки Model-View-ViewModel (MVVM).
  • Наконец, эти редакторы на самом деле не редактируют классы напрямую. Вместо этого они оперируют XML-файлами, содержащими метаданные (LightSwitch Markup Language), которые потом используются настраиваемыми задачами MSBuild для генерации кода на этапе компиляции. В итоге это освобождает вас от выбора технологий в прикладной логике. Так, проект LightSwitch в версии 1.0 будет использовать WCF RIA Services для всех коммуникаций между клиентом и сервером, тогда как тот же проект теперь компилируется с применением сервиса Open Data Protocol (OData) (подробнее об OData позже). Благодаря этому достигается максимально высокая адаптируемость под вечно меняющийся ландшафт IT.

Проектирование данных

Проектирование данных с помощью LightSwitch можно рассматривать как эквивалент создания моделей предметной области, если использовать лексикон профессионального разработчика. IDE сначала запрашивает вас о начале работы с данными, а именно о том, где вы хотите хранить эти данные. Доступно два ответа. Вы можете выбрать «Create new table» (создать новую таблицу), и тогда LightSwitch использует Entity Framework для создания необходимых таблиц в базе данных SQL Compact (при отладке приложения), SQL Server или Microsoft Azure SQL. Или же предпочесть проектирование своих сущностей поверх существующего источника данных, например SharePoint, OData-сервиса, имеющейся базы данных или сборки WCF RIA Services. Последние два варианта могут быть по-настоящему полезны, если вы продолжаете работать с существующим набором данных от устаревшего приложения, но хотите предоставлять к ним доступ через современные и открытые стандарты в совершенно новом сервисе или приложении.

В качестве примера можно взять существующий OData-сервис (обширный список примеров доступен на odata.org/ecosystem) и импортировать одну или несколько сущностей в новое приложение LightSwitch.

На рис. 1 показано, как сущность Employee из источника данных Northwind поначалу представляется в Entity Designer. С помощью нескольких щелчков мыши и минимумом усилий в кодировании, где это нужно, вы можете перепроектировать эту сущность в нескольких отношениях (конечный результат приведен на рис. 2), а именно:

  • переименовать или переупорядочить свойства (TeamMembers и Supervisor);
  • настроить списки выбора для свойств, которые должны принимать лишь ограниченное количество заранее определенных значений (City, Region, PostalCode, Country, Title и TitleOfCourtesy);
  • добавить новые или вычисляемые свойства (NameSummary);
  • сопоставить более детализированные бизнес-типы с типом данных какого-либо свойства (BirthData, HireDate, HomePhone, Photo и PhotoPath).

Entity Designer после импорта из существующего OData-сервиса
Рис. 1. Entity Designer после импорта из существующего OData-сервиса

Та же сущность Employee после перепроектирования
Рис. 2. Та же сущность Employee после перепроектирования

LightSwitch распознает большой набор часто используемых бизнес-типов, таких как E-mail Address и Phone Number, а дополнительные типы можно найти во множестве доступных расширений либо создать самостоятельно через проект расширения LightSwitch. Что касается нижележащего типа данных, то бизнес-типы дополняют какое-либо свойство особыми характеристиками вроде специализированных проверок (например, форматов адресов электронной почты или веб-адресов) и специфическими расширяемыми свойствами (форматы телефонных номеров для бизнес-типов Phone Number) и зачастую поставляются со специальными элементами управления, используемыми (по умолчанию) для представления этого свойства в клиентском приложении или для взаимодействия с ним.

Сущности никогда не бывают не взаимосвязанными. С помощью Entity Designer вы можете указывать отношения между различными сущностями. Эти отношения будут введены в действие на всех уровнях — через код в клиенте и промежуточном уровне и через внешние ключи в базе данных, когда спроектированные сущности будут сохранены в выбранном (новом) источнике данных, например базе данных SQL Compact, SQL Server или Microsoft Azure SQL.

Однако по-настоящему мощная функция LightSwitch заключается в том, что вы можете определять новые отношения и в существующих источниках данных. Это особенно удобно, когда приходится работать с существующими наборами данных, такими как XML-файлы или старые базы данных с неподходящим форматом без индексов, ключей или необходимыми отношениями. Данная функция позволяет вводить так называемые виртуальные отношения (virtual relationships) в клиенте и промежуточном уровне, не модифицируя устаревший источник данных. Еще важнее, что эти виртуальные отношения могут быть определены между сущностями, находящимися в разных источниках данных.

Например, щелкнув правой кнопкой мыши Data Sources в Solution Explorer и выбрав Add Table, вы можете создать новую сущность Holiday, которая будет храниться в новой базе данных, где у нее будут виртуальные отношения с сущностью Employee из базы данных Northwind, предоставляемой через OData-сервис (рис. 3).

Виртуальные отношения, охватывающие разные источники данных
Рис. 3. Виртуальные отношения, охватывающие разные источники данных

Создание приложения для отслеживания отпусков (holidays) таким способом — отличный пример того, как LightSwitch помогает проникать через границы данных одного приложения и открывать к ним доступ в другом приложении.

Формирование данных

LightSwitch пытается удерживать на минимальном уровне объем кода, необходимый для того, чтобы приступить к работе; это значительно ускоряет начальные этапы разработки. Прежде чем сервис данных будет готов реально предоставлять доступ к данным, зачастую требуются некоторые оптимизации и модификации в формировании этих данных. Во многих случаях это легче выразить в коде, чем с помощью редактора.

Для каждого события в LightSwitch имеется точка расширения, доступная через дизайнер по кнопке Write Code (рис. 4). В зависимости от того, будет ваш код вызываться на сервере, клиенте или на обоих уровнях, нажатие данной кнопки приведет к генерации метода-заглушки (method stub), где вы сможете вставить свой код в клиентский, общий или серверный подпроект проекта LightSwitch.

LightSwitch поддерживает множество точек расширения
Рис. 4. LightSwitch поддерживает множество точек расширения

Если продолжить пример с приложением для отслеживания отпусков, то вы могли бы использовать эти точки расширения кодом для инициализации какой-либо сущности. Так, следующий код будет автоматически назначать начальника отдела, где работает сотрудник, в качестве лица, одобряющего его заявление на отпуск, или самостоятельно утверждать заявление на отпуск, если у данного сотрудника нет начальника:

public partial class ApplicationDataService
{
  // Инициализация новой Holiday – только для сервера
  partial void Holidays_Inserting(Holiday entity)
  {
    if (entity.Employee.Supervisor != null)
      entity.ApprovalBy = entity.Employee.Supervisor;
    else
      entity.Approved = true;
  }
}

Аналогично эти точки расширения с помощью кода помогают писать собственный код проверок, выходящих за рамки того, что уже проверяется бизнес-типом свойства:

public partial class Holiday
{
  // Определяем, допустимо ли значение EndDate;
  // выполняется на клиенте и сервере
  partial void EndDate_Validate(EntityValidationResultsBuilder results)
  {
    if (StartDate > EndDate)
      results.AddPropertyError("End date must follow the start date");
  }
}

Помимо поддержки собственных проверок и бизнес-правил, LightSwitch также предлагает встроенную (необязательную) модель управления доступом, основанную на ролях и разрешениях. Проверки для управления доступом тоже можно выполнять из этих точек расширения, причем можно использовать как горизонтальную модель управления доступом, так и вертикальную.

Вертикальная модель управления доступом (vertical access control) подразумевает ограничения по экранам, сущностям или свойствам на основе разрешений текущего пользователя. Например, следующий код ограничивал бы процесс утверждения только теми сотрудниками, которые работают в определенном отделе организации, скажем, в отделе кадров:

public partial class Holiday
{
  // Определяем, может ли данный пользователь изменять
  // "Approved"; выполняется на клиенте и сервере
  partial void Approved_IsReadOnly(ref bool result)
  {
    result = !Application.User.HasPermission("ApproveHolidays");
  }
}

Горизонтальная модель управления доступом (horizontal access control) подразумевает фильтрацию записей, видимых конечному пользователю. Заметьте, что этот код выполняется на серверном уровне, а значит, данные, к которым не разрешен доступ конечному пользователю, никогда не передаются по сети:

public partial class ApplicationDataService
{
  // Фильтрация записей; выполняется только на сервере
  partial void Holidays_Filter(ref Expression<Func<Holiday, bool>> filter)
  {
    if (!Application.Current.User.HasPermission("ViewAllHolidays"))
      filter = holiday => holiday.Employee.NameSummary ==
        Application.Current.User.FullName ||
        Application.Current.User.FullName == holiday.ApprovalBy.NameSummary;
  }
}

Горизонтальное управление доступом, также называемое защитой уровня записей (row-level security), — важное дополнение LightSwitch в Visual Studio 2012.

Прежде всего фильтр выполняется на сервере. Это ограничивает объем данных, которые иначе впустую передавались бы по сети при каждом вызове, — пользователю ведь не разрешено взаимодействовать с этими записями. При вертикальном управлении доступом конечный пользователь видит данные, даже если он не может взаимодействовать с ними; они доступны только для чтения, а в случае несанкционированных действий генерируются исключения. Однако при горизонтальном управлении доступом лишние данные полностью скрываются от конечного пользователя.

Это приводит нас к другой важной области использования защиты на уровне записей: она позволяет выдавать права владения теми или иными частями набора данных только конкретным пользователям или организациям. Тем самым вы можете создать приложение, которое потребуется установить лишь раз, а потом предоставлять доступ различным группам, компаниям, индивидуальным лицам или организациям. Каждый из них выступает в роли владельца (tenant) в том плане, что все они используют одно и то же клиентское приложение и те же сервисы, но владеют только своей частью данных. Такие мультитенантные системы колоссально сокращают расходы на хостинг для всех сторон и обеспечивают другие преимущества вроде возможности обновления всего сразу в одном центральном месте, например в облаке. Те, кто имел удовольствие тратить часы, подключаясь к локальным серверам для обновления срочным исправлением одной установленной системы за другой, вероятно, первыми оценят мощь поддержки мультитенантных возможностей в LightSwitch 2012.

Предоставление доступа к данным

Размышляя о ценности данных, собираемых какой-либо компанией, многие склонны учитывать только то, что относится к продукту, использующему эти данные. Однако сбор и анализ разнообразных категорий данных становится все важнее сам по себе. Освобожденные от оков единственного приложения и при правильном применении, анализ и просеивание данных может дать дополнительную прибыль вне рамок традиционной бизнес-модели, основанной на традиционных продуктах. Чтобы это работало, важно использовать открытые стандарты, такие как протокол OData, который применяется в сервисе, автоматически создаваемом при создании проекта LightSwitch.

Вот выдержки по OData с сайта odata.org.

«OData, сокращение от Open Data Protocol, — это веб-протокол для запроса и обновления данных… OData осуществляет это применением и опорой на (открытые) веб-технологии, такие как HTTP, Atom Publishing Protocol и JSON… OData согласуется с тем, как работает Web: он глубоко привержен идее URI для идентификации ресурсов и придерживается унифицированного интерфейса на основе HTTP для взаимодействия с этими ресурсами (точно так же, как Web). Эта приверженность базовым принципам Web позволяет OData обеспечить новый уровень интеграции данных и взаимодействия с ними широкого спектра клиентов, серверов, сервисов и различных инструментальных средств».

Иначе говоря, OData реализует сервис, с которым можно взаимодействовать, используя простые HTTP-команды и идентификаторы ресурсов (или URL). OData-сервис может быть использован почти любой клиентской технологией, и в простейшем случае это означает, что такой сервис можно просматривать даже с помощью HTTP-запроса Get из веб-браузера, набрав, например, следующую строку в качестве веб-адреса:

http://services.odata.org/Northwind/Northwind.svc/Customers?$filter=

replace(CompanyName, '%20','')eq'AlfredsFutterkiste'

Такой URL всегда состоит из корневого URL сервиса (его конечной точки), пути к ресурсу (имени сущности) и дополнительно (но не обязательно) параметров запроса. Заметьте, что последний делаем сам сервис весьма агностическим по отношению к сценариям применения; протокол OData предоставляет довольно богатый язык запросов, который можно использовать для сортировки и фильтрации данных по URL так, как это нужно вызвавшему. Полный список операторов см. по ссылке bit.ly/LSiPAj.

Проектируя сервис данных в LightSwitch и понимая, как будут использоваться данные, вы можете также задействовать преимущества Query Designer для создания запросов до публикации. На рис. 5 показан простой запрос, который возвращает только неутвержденные отпуска, начиная с текущего года. Заметьте, что источником для запроса является весь набор Holidays, и он, конечно же, будет заранее фильтроваться с помощью фильтра, указанного мной в коде ранее.

Построение простого запроса с помощью Query Designer
Рис. 5. Построение простого запроса с помощью Query Designer

Поработав в Entity Designer и Query Designer, вы, возможно, закончили с OData-сервисом, и он готов к развертыванию. Это можно сделать прямо из Visual Studio IDE, щелкнув правой кнопкой мыши проект LightSwitch в Solution Explorer и выбрав «Publish…» из контекстного меню.

В результате на экране появится LightSwitch Publish Application Wizard (рис. 6), с помощью которого можно настроить некоторые специфические свойства финальной версии приложения, например необходимые строки подключения, типы аутентификации (без аутентификации [None], на основе имени и пароля пользователя или средствами Windows), учетную запись администратора приложения и вид установки (установочный пакет или прямая публикация в IIS либо в Microsoft Azure из IDE). Последний вариант значительно усовершенствован за последние несколько месяцев, что ускоряет развертывание вашего сервиса данных в облаке и делает его беспроблемным.

LightSwitch Publish Application Wizard
Рис. 6. LightSwitch Publish Application Wizard

За счет поддержки открытых стандартов с этим сервисом данных сможет взаимодействовать целый набор клиентов, которые почти наверняка уже есть у каждого конечного пользователя. Приложения электронных таблиц вроде Microsoft Excel позволяют использовать сервис данных и превращать его данные в PowerPivot-таблицы и диаграммы безо всякого дополнительного кодирования (рис. 7). (Заметьте: PowerPivot, встроенный в Office 2013, является отдельной бесплатной надстройкой для Office 2010.) Пошаговую инструкцию по всем операциям вы найдете по ссылке bit.ly/xETG0V.

Использование OData-сервиса LightSwitch в Excel
Рис. 7. Использование OData-сервиса LightSwitch в Excel

Создание клиентов

Другое ключевое преимущество LightSwitch заключается в том, что вы можете использовать ту же IDE для создания клиентских приложений. LightSwitch поддерживает как толстые клиенты (Silverlight 5, приложения, выполняемые в браузере или вне браузера), так и мобильные приложения (HTML5); при этом скорость их разработки ничуть не меньше, а иногда даже быстрее, чем на серверной стороне. Заметьте, что поддержка создания HTML5-приложений будет доступна в виде надстройки для финальной версии Visual Studio 2012.

Чтобы приступить к созданию клиентского приложения, щелкните кнопку Add Screen либо в Entity Designer, либо в Query Designer. Появится мастер, где вы выберете шаблон экрана, который может быть одним из множества встроенных шаблонов, разработанным вами или скачанным из доступных расширений.

После выбора данных для экрана (набора сущностей Holidays) и шаблона (экрана списка и детальных сведений) будет сгенерирована необходимая разметка, и она появится в дизайнере экрана. После этого вы сможете вносить изменения в разметку элементов управления или полностью поменять используемые элементы управления. LightSwitch делает максимум возможного, чтобы предложить оптимальный элемент управления на основе бизнес-типа какого-либо свойства, например элемент выбора дат для свойства, содержащего даты рождения, но вы свободно можете заменить его на другой элемент управления LightSwitch — готовый или загруженный из доступных расширений. Или задействовать свои навыки в XAML (либо в JavaScript и CSS) и модифицировать элемент управления самостоятельно так, как вам нужно. На этом этапе приложение готово к сборке и выполнению — достаточно нажать клавишу F5.

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

Как видно на рис. 8, приложение получается четким, интуитивно понятным и полностью функциональным. Однако пусть вас не обманывает простота, с которой оно было создано. В частности, «за кулисами» оно использует новейшую версию MVVM с интерпретацией метаданных, о которой я рассказывал в статье «The LightSwitch MVVM Model» за апрель 2012 г. (msdn.microsoft.com/magazine/hh965661). Ввиду этого Screen Designer, который использовался в Visual Studio для подготовки начального дизайна, можно вызвать внутри приложения, щелкнув ссылку на дизайнер экрана в нижней правой части; это позволит вносить дальнейшие изменения в метаданные представления, пока приложение выполняется в отладочном режиме. Потом эти изменения можно будет сохранить в проекте.

Простое клиентское приложение LightSwitch
Рис. 8. Простое клиентское приложение LightSwitch

При дальнейшем изучении клиентской архитектуры LightSwitch вы обнаружите гораздо больше технологических чудес. Так, элементы управления или экраны будет автоматически становиться доступными только для чтения или вообще скрываться, если у вас недостаточно разрешений для редактирования нижележащей сущности.

Не менее удобно и то, что вам больше не нужно беспокоиться о самостоятельной генерации событий NotifyPropertyChanged для корректной работы ваших привязок. Если конечный пользователь изменяет, например, свойство с фамилией, принадлежащее сущности Employee, элемент управления, связанный с вычисляемым свойством fullname, будет автоматически обновлен для отображения нового значения.

Все модели, применяемые в клиенте, на самом деле являются дуальными диспетчерскими объектами (dual-dispatcher objects), помогающими сохранять отзывчивость UI при обработке прикладной логики. Из UI-потока вы можете просто назначить некое значение какому-либо свойству. На внутреннем уровне это приведет к отправке уведомления, которое извлекается на основе взвешенного приоритета вторым потоком, называемым логическим (logical thread). Как только обработка прикладной логики завершается, применяется та же система уведомления о событиях, и UI-поток информируется об окончательном результате, после чего соответственно обновляется.

И последний интересный факт, о котором я хотел упомянуть в связи с обсуждением клиентских приложений, взят из блога группы Visual Studio LightSwitch, где объясняется, что каждый экран на деле представляет собой единицу работы (см. bit.ly/9vENdF). У каждого экрана своя рабочая область данных (data workspace), которая используется совместно с любым открытым дочерним экраном. Все изменения запоминаются локально, пока конечный пользователь не решит сохранить их или отбросить. Это означает, что, дважды открыв какой-нибудь экран (создание нескольких экземпляров по умолчанию запрещено, но это можно разрешить в окне Properties из Screen Designer), вы можете имитировать то, как LightSwitch обрабатывает разных пользователей, одновременно вносящих изменения в какие-то данные, а затем сохраняющие их — тоже одновременно (рис. 9).

Обработка параллельных изменений
Рис. 9. Обработка параллельных изменений

Если вас интересует, насколько хорошо LightSwitch справляется с такими ситуациями, то, как я сказал во введении, он не просто удовлетворяет всем требованиям — он намного превосходит их.


Ян ван дер Хаген (Jan Van der Haegen) — энтузиаст, «превращающий кофе в программы». Любящий муж, специалист по SCRUM-митингам в международной группе в центральной части Бельгии, увлечен изучением всего, что относится к технологии .NET, в том числе интересуется Visual Studio LightSwitch. Ведет блог по своим экспериментам в кодировании. Его последние приключения вы найдете в switchtory.com/janvan.

Выражаю благодарность за рецензирование статьи экспертам Джо Байндеру (Joe Binder) и Бет Масси (Beth Massi).