Основы «Oslo»

Создание приложений на основе метаданных при помощи платформы «Oslo»

Крис Селлс (Chris Sells)

Эта статья основана на предварительной версии платформы «Oslo». Любые содержащиеся в ней сведения могут быть изменены.

В этой статье рассматриваются следующие вопросы.
  • «Oslo» и метаданные
  • MGraph и MSchema
  • Сценарии SQL, упаковка и развертывание
  • Интеграция с Visual Studio
В этой статье используются следующие технологии.
«Oslo», SQL Server 2008

Cодержание

Метаданные
Сборка на основе «Oslo»
MGraph и MSchema
Создание SQL
Пакетирование и развертывание
Интеграция с Visual Studio
Пример кода

Приложение, основанное на Microsoft .NET Framework, обычно определяется набором скомпилированного кода и набора связанных ресурсов. Например, приложение ASP.NET определяется скомпилированным кодом (сборками), предоставляющим логику для веб-узла, и файлами ресурсов (файлами .aspx), определяющими сами страницы. Код выполняется центральным процессором (после компиляции), а страницы интерпретируются средой выполнения ASP.NET. Сходным образом, Windows Workflow Foundation (WF) позволяет определять поведение как набор настроенных действий, которые представляют собой просто данные, которые интерпретируются средой выполнения WF.

Если объединить ASP.NET со стороны пользовательского интерфейса и WF на стороне поведения, то можно представить себе создание целых приложений практически исключительно из данных с использованием кода только для заполнения поведений, не предоставленных средами выполнения.

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

Корпорация Майкрософт создает «Oslo», платформу для сборки приложений на основе данных, с целью разработки общего набора средств для определения метаданных, которые можно было бы хранить в месте, которое предоставляет набор возможностей, аналогичный нормальным данным приложения. «Oslo» состоит из трех элементов: семейства языков, которые вместе называются «M», визуального средства работы с данными под названием «Quadrant» и хранилища данных, которое называется репозиторием.

В этой статье мы рассмотрим ряд принципов, лежащих в основе платформы «Oslo». Кроме того, будет дано введение в средства и технологии, которые понадобятся для реализации этих принципов. В частности, я расскажу, как «Oslo» позволяет создавать приложения на основе метаданных с помощью средств MSchema и MGraph, а также основы определения типов и значений в «M» и развертывания их в репозиторий.

«Olso»: новый способ реализовать старую идею

В самой идее инфраструктур на основе данных нет ничего нового. Вот, например, платформа Windows Presentation Foundation (WPF). При создании большинства приложений WPF основная часть приложения состоит из кода XAML, загружаемого во время выполнения и интерпретируемого анализатором XAML. Именно метаданные отвечают за определение приложения WPF. Можно даже изменить определение приложения WPF, во время выполнения загрузив или создав код XAML, о котором разработчик не знал во время компиляции.

Но в коде XAML (который компилируется в форму, известную как BAML), упакованном в ресурс вместе с кодом приложения, нет ничего удивительного; его точно так же можно было загрузить в отдельный файл или даже в реляционную базу данных. Если бы он был загружен в базу данных, загрузчик WPF выполнил бы запросы SQL для доступа к определениям приложения вместо того, чтобы загружать ресурсы; но в остальном пользователь не заметил бы разницы. А если определение приложения загружено из базы данных, все данные можно обновлять централизованно, что позволит разработчикам приложения распространять изменения без повторения развертывания приложения для каждого клиента, которому нужно его выполнять. Это самое потрясающее свойство Интернета, ради которого стоит работать над любыми приложениями, выполняющимися в обозревателе или отдельно.

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

И наконец, определения приложений можно использовать не только для управления одним экземпляром приложения. Их можно использовать во время разработки, чтобы проверить, работают ли определенные части приложения в соответствии со спецификациями. Их можно использовать во время выполнения и посмотреть, какие части используются, а с какими есть затруднения. Их можно использовать для разметки ошибок, чтобы разработчики видели, что именно вызывает затруднения. Если у вас есть метаданные приложения, у вас есть весь спектр возможностей запросов современной, индексированной, настроенной, размноженной, безопасной, снабженной контролем версий, локализованной, способной работать вне Инернета базы данных.

Это в точности платформа «Oslo» — использование широких возможностей SQL Server для хранения метаданных приложения. Использование метаданных для управления поведением приложения применялось в Windows по меньше мере с тех пор, как мы начали помечать двоичные файлы битом консоли, чтобы получать окно консоли без написания кода. «Oslo» — это просто формализация и приведение к общему виду метаданных приложения и обеспечение им той же широты возможностей и средств, что и для данных приложения.

Метаданные

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

Вот, например, метаданные, описывающие текстовый редактор, который я использую для набора этой статьи, не менялись с момента его выпуска в 2007 году, а данные изменялись тысячи раз только за сегодняшний день, когда я набирал буквы и двигал мышью, чтобы поменять что-нибудь в документе. Метаданные так редко подвергаются записи, что иногда их поставляют в пакетах, доступных только для чтения, как определения классов в сборке .NET или прекомпилированные файлы XAML, встроенные в сборку в виде ресурсов. Так как разработчики часто пишут приложения на основании статической природы метаданных, как у обработчиков событий для кнопки, определенных на странице ASP.NET, не так уж плохо менять метаданные приложения изредка.

Но вот что плохо в современной инфраструктуре метаданных — то, что средства для определения и чтения метаданных принципиально отличны от средств, которые использовались бы для данных приложения.

Я могу разработать приложение, считывающее и записывающее данные через реляционную базу данных, которая обеспечит широкий набор средств для таких вещей, как запросы, безопасность, репликация и контроль версий. Но если нужно создавать запросы к метаданным .NET Framework, у меня куда более ограниченный набор средств: в общем-то, только интерфейс API отражения.

Более того, средства .NET Framework для работы с метаданными сильно отличаются от средств для того, чтобы открывать метаданные SQL. Если нужно создавать запросы между данными и метаданными приложения, то есть запросы по выполняемым рабочим процессам и определениям этих процессов, придется создавать собственные средства, потому что источники данных разные: SQL и файлы языка Extensible Object Markup Language (XOML).

Сборка на основе «Oslo»

С помощью «Oslo» можно собирать различные вещи. Когда мы говорим между собой о вариантах, беседа часто доходит до создания приложений, включающих данные. Можно заметить, однако, что среди вещей, входящих в «Olso», я не упомянул сред выполнения. Действительно, файлы .aspx не очень полезны без ASP.NET, а файлы XOML совсем не так хороши без WF.

Разрабатывается несколько сред выполнения и служб, которые будут использовать «Oslo». Сюда входит новая версия ASP.NET, поддерживающая язык предметной области (DSL) MWeb и веб-редактор «Quadrant», расширения Windows Server «Dublin», поддерживающие DSL «MService» и редактор служб «Quadrant», инфраструктура сущностей, поддерживающая DSL MEntity, и редактор элементов «Quadrant» и SQL Server 2008 с языком MSchema (о котором пойдет речь ниже в этой статье) и редактором схем «Quadrant». Можно будет загружать данные в репозиторий и управлять этими средами выполнения.

Репозиторий «Oslo» рассчитан на приложения, для которых корпоративные разработчики создали собственные хранилища для метаданных, сходные с репозиториями. Например, «Oslo» будет хорошей платформой для репозитория информации о настройках машины, позволяющего операторам опрашивать и легко усваивать настройки машины; или, подобным же образом, для репозитория эксплуатационных процедур и сценариев. Разработчикам тот факт, что репозиторий предоставляет единое зранилище для метаданных, поддерживающее запросы, даст возможность ответить на такие вопросы, как «какие приложения и классы реализуют определенный метод?» и «повлияет ли изменение этого метода на производительность?»

Еще одна область возможного применения «Oslo» — ознакомление с распределенными приложениями. Объединение профилирования, покрытия кода, нагрузочного тестирования и данных архитектуры в репозитории позволит разработчикам, например, быстро решать проблемы производительности, переходя к нужному распределенному компоненту, изучая значения различных параметров настройки и просматривая подробности реализации. Кроме того, это позволит разрабатывать средства статического анализа, автоматически сообщающие о недостатках проектирования.

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

Приведу пример: веб-сайт центра загрузок Microsoft позволяет клиентам делать загрузки разного размера. Размещаемые на этом сайте файлы должны быть пакетированы в файл установщика Microsoft (MSI) и помечены лицензионным соглашением для конечного пользователя (EULA). Сделав это раз пять с помощью графического пользовательского интерфейса в Visual Studio, я начал искать автоматическое решение и нашел таковое в коде XML установщика Windows (WiX), позволяющем использовать код XML для определения установки и компиляции ее в файл MSI.

На рис. 1 показан пример кода XML WiX. Для непривычного глаза это может показаться не лучше, чем работа с графическим интерфейсом, но если сделать те же 27 движений мышкой несколько раз, программист внутри вас наверняка возьмет верх.

Figure 1 XML WiX для создания файла MSI

<?xml version='1.0' encoding='Windows-1252'?>
<Wix xmlns="https://schemas.microsoft.com/wix/2006/wi">
  <Product Name="SuperNotepad" Id="d65d2125-560b-4ba9-bdca-3b3bcd3f7b70"
           UpgradeCode="ac5c9dac-b3f0-469a-8f1a-02c2566eee33" 
           Language="1033" Codepage="1252"
           Version="1.0.0.0" Manufacturer="SuperNotepad Corp.">
    <Package Description="A really super pad for notes" 
             Manufacturer="SuperNotepad Corp."
             InstallerVersion="200" Languages="1033" Compressed="yes" />
    <Media Id="1" Cabinet="setup.cab" EmbedCab="yes" />
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder" Name="ProgramFilesFolder">
        <Directory Id="Directory3" Name="SuperNotepad Corp.">
          <Directory Id="INSTALLDIR" Name="Better NotePad">
            <Component Id="Component1" 
                       Guid="f7554ac8-32cd-44fb-bf85-0559c7d2e15c">
              <File Id="File1" Name="Manual.txt"
                    Source="C:\temp\SuperNotepad\Files\manual.txt" />
              <File Id="File2" Name="dependency.dll"
                    Source="C:\temp\SuperNotepad\Files\dependency.dll" />
              <File Id="File3" Name="BetterNotePad.exe"
                    Source="C:\temp\SuperNotepad\Files\notepad.exe" />
            </Component>
          </Directory>
        </Directory>
      </Directory>
    </Directory>
    <Feature Id="Feature1" Level="1">
      <ComponentRef Id="Component1" />
    </Feature>
  </Product>
</Wix>

MGraph и MSchema

Даже несмотря на то, что я могу в некоторой степени автоматизировать создание кода XML WiX, я не очень хочу писать установки в море угловых скобок. «Oslo» позволяет мне записывать их на «M», семействе языков, состоящем из MSchema, MGrammar и MGraph. (Спецификации MSchema и MGrammar можно найти на страницах «Спецификация языка моделирования «Oslo»» и «Спецификация языка MGrammar», соответственно.)

Кратко рассмотрим MGraph и MSchema (об MGrammar я расскажу в следующей статье). Если вы хотите поработать дома, я очень рекомендую средлство Mr. Epl, входящий в комплект SDK для платформы «Oslo». («Mr. Epl» — так мы произносим MREPL.EXE, аббревиатуру от M Read-Evaluate-Print-Loop (чтение-оценка-печать-цикл).) Его можно использовать из текстового редактора Intellipad, входящего в комплект SDK для платформы «Oslo», выбрав Intellipad (Samples Enabled) в меню «Пуск», нажав Ctrl+/ для вызова мини-буфера и набрав «SetMode('MScriptMode')» (без кавычек, соблюдая регистр), а затем нажав ВВОД.

MGraph — язык для определения экземпляров структурированных данных (которые больше известны как значения). В этом примере я определил три фрагмента данных: анонимное целое число, анонимный набор трех целых чисел и запись под названием «pt1» с двумя полями, X и Y, оба целые числа.

42
{ 1, 2, 3 }
pt1 { X = 10, Y = 20 }

MSchema — язык для определения ограничений для данных. В MSchema набор ограничений связывается в типы. Здесь я определил два именованных типа: тип SmallInteger, ограничивающий тип Integer32 значением меньше 256, и тип элемента Point (название типов записей в M) с двумя полями X и Y.

type SmallInteger : Integer32 where value < 256;
type Point { X : Integer32; Y : Integer32; };

X и Y ограничиваются целыми значениями от -2 147 483 648 до 2 147 483 647.

Если вы читаете эту статью, вы, очевидно, знакомы с CLR. В CLR используется то, что называется «номинальной типизацией», то есть присвоение имени одному типу, к которому принадлежит значение. «M», с другой стороны, основывается на структурной типизации, как XML. В мире структурной типизации значение может принадлежать любому числу типов, если данные соответствуют ограничениям, установленным этим типом. Для проверки того, попадает ли значение в набор, определенный типом, используется операция «in» (здесь она показана внутри средства Mr. Epl):

M>>> type SmallInteger : Integer32 where value < 256;
M>>> 4 in SmallInteger
true
M>>> 4 in Integer32
true
M>>> 256 in SmallInteger
false
M>>> 256 in Integer
true

Здесь можно видеть, что 4 — SmallInteger и Integer32, а 256 — только Integer32. Значения сущностей тоже можно проверять на принадлежность к типу.

M>>> type Point { X : Integer32; Y : Integer32; };
M>>> { X = 100, Y = 200 } in Point
true
M>>> pt1 { X = 10, Y = 20 }
M>>> pt1 in Point
true
M>>> pt1 in { X : SmallInteger; Y : SmallInteger; }
true
M>>> pt1 in { X; Y; }
true

Можно видеть, что именованные и неименованные пары X, Y относятся к Point и что оба поля названной пары X, Y — значения SmallInteger, здесь определяющие анонимный тип, выполняющий за вас проверку. Последняя строка означает, что именованная пара X, Y попадает в набор значений, у которых поля названы как X и Y, без ограничений на значения: они могут быть строками, датами или коллекциями или чем угодно.

Еще один пример. В этом случае, так как у названной пары X, Y нет поля Z, она не попадает в анонимный тип, требующий полей X, Y и Z.

M>>> pt1 in { X; Y; Z; }
false
M>>> pt1 in { x; y; }
false

В последней строке видно, что M зависит от регистра символов.

Наконец, нужно ознакомится с записями для значения по умолчанию и коллекции:

type Product {
    Name : Text;
    ...
};

type Package {
    Product : Product; // required value
    Keywords : Text*; // collection of 0 or more values
    Description : Text?; // optional value
    Comments : Text?; // optional value
    Manufacturer : Text; // required value
    InstallerVersion : Integer32 = 200; // default value
    Language : Integer32 = 1033; // default value
    Compressed : Logical = true; // defaults value
};

Здесь вы видите тип Package из модуля WiX. У всех продуктов (элемент верхнего уровня в установке MSI) есть пакет, содержащий необязательный набор текстовых ключевых слов, необязательное описание и комментарий, обязательное название производителя, версию установщика (по умолчанию установщик Windows 2.0), язык по умолчанию — английский США и флаг сжатия, по умолчанию имеющий значение «истина».

У обязательных значений нет суффикса, например Product и Manufacturer. Значения по умолчанию имеют знак равенства и значение, например InstallerVersion и Language. У необязательных значений есть суффикс в виде знака вопроса, например Description и Comments. Значения коллекции (с нулем или более значений) заканчиваются звездочкой. Отметки в виде знака вопроса и звездочки (? и *) должны напоминать вам операции Клини из вашего любимого языка регулярных выражений.

Вот пример значения Package:

Products { 
    SuperNotepad : Product* {
        Name = "SuperNotepad",
        ...
    }
}

Packages : Package* where item.Product in Products {
    Package1 {
        Product = Products.SuperNotepad,
        Description = "A really super pad for notes",
        Manufacturer = Products.SuperNotepad.Manufacturer,
        Keywords = { "Installer", "Super", "Notepad", "Sample" }
    }
}

Здесь у меня часть Product и целый Package. Заметьте, что у меня есть два типа ограничений. Первый — в виде ": something", как в:

SuperNotepad : Product* {

Это называется припиской типа и обязывает все значения в фигурных скобках удовлетворять требованиям типа.

Второе ограничение — указание компилятору «М» о том, где искать хранилище для значений элементов Product.

Packages : Package* where item.Product in Products {

Заметьте также, что у двух значений есть названия (SuperNotepad и Package1). Синтаксис MGraph позволяет использовать названия в середине инициализации графа значений, чтобы одна часть графа могла ссылаться на другую без копирования данных. Я делаю это для того, чтобы сослаться на свой продукт в определении пакета.

Mr. Epl — очень полезный инструмент, но для больших файлов лучше использовать текстовый редактор. И Visual Studio 2008, и Intellipad предоставляют языковые службы, которые делают редактирование «М» сплошным удовольствием. Например, для провеки правильности синтаксиса можно просто искать советы над красными тильдами, которые показывают ошибки (например, нет закрывающих двойных кавычек).

Весь код «M» должен быть внутри модуля, во многом аналогично тому, как код на основе .NET должен быть в пространстве имен. Таким образом определяются обдасти действия типов и значений.

Если отсутствия тильд вам мало для полного счастья, можно запустить из командной строки компилятор «М»:

C:\>set path=%path%;"c:\Program Files\Microsoft Oslo SDK 1.0\Bin"
...
C:\>m.exe /t:none wixbits.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.
C:\>

Если компилятор «M» не сообщает об ошибках, код чист. Заметьте, что я не только передаю m.exe файл с расширением .m, но и указываю пустую цель (с помощью флажка /t). Это значит, что нужно просто выполнить проверку синтаксиса. Без флажка цели компилятор «M» попытается использовать вашу программу для порождения (автоматического создания) сценария SQL для создания таблиц и вставки значений.

Автоматическое создание кода SQL

Если вы попытаетесь автоматически создать код SQL из примера данных модели WiX (добавив закрывающую кавычку), вы получите похожий на приведенный ниже отчет об ошибке.

C:\>m wixbits.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.

C:\wixbits.m(16,9): error M2010: The referenced type 'Product' does not define an identity constraint.
...

Это сообщение об ошибке можно получить, если выбрать M Mode|Reach SQL Preview из-под Intellipad. Происходит следующее: компилятор «M» пытается создавать сценарий SQL, соответствующий типам и значениям, определенным в программе. Это он делает, пытаясь сопоставить именованные значения высшего уровня (они называются экстентами) для создания операторов table и сопоставить сами значения с операторами insert. Но так как у «M» есть всевозможные использования общего описания данных, не всё в нем можно сопоставить с конструкциями SQL, например, типы сущностей без полей идентификации. Это всё еще допустимый язык «M», но уже недопустимо для автоматическиого создания кода SQL.

Автоматическое создание кода SQL — действие по умолчанию компилятора «М», потому что современная реляционная база данных — отличная среда для хранения данных и работы с ними. У нее есть всевозможные замечательные возможности, такие как безопасность, репликация, контроль версий, аудит и так далее. Если вы используете SQL Server для размещения данных, вы получаете все эти возможности, а также немало устойчивости и оптимизаций производительности.

Для того, чтобы типы «M» были совместимы с SQL Server, сопоставление требует столбца идентификации, который можно добавить с помощью следующего кода.

type Package {
    Id : Integer32 = AutoNumber();
    ...
} where identity Id;

Как видите, я создаю поле с названием Id и использую функцию AutoNumber для установки значения по умолчанию. Затем я добавляю ограничение на тип, используя ключевое слово «where», отмечаюшее поле Id как столбец идентификации. Теперь у меня достаточно данных для получения допустимого кода SQL для этого типа, как показано на рис. 2.

Рис. 2 Код SQL, автоматически созданный языком «M»

...
create table [WixBits].[Packages](
  [Id] int not null identity,
  [Comments] nvarchar(max) null,
  [Compressed] bit not null default 1,
  [Description] nvarchar(max) null,
  [InstallerVersion] int not null default 200,
  [Language] int not null default 1033,
  [Manufacturer] nvarchar(max) not null,
  [Product] int not null,
  constraint [PK_Packages] primary key clustered ([Id]),
  constraint [FK_Packages_Product_WixBits_Products] foreign key ([Product]) references [WixBits].[Products] ([Id])
);
...

create table [WixBits].[Packages_Keywords](
  [_Id] bigint not null identity,
  [Packages_Id] int not null,
  [Item] nvarchar(max) not null,
  constraint [PK_Packages_Keywords] primary key clustered ([_Id]),
  constraint [FK_Packages_Keywords_Packages_Id_WixBits_Packages] foreign key 
  ([Packages_Id]) references [WixBits].[Packages] ([Id]) on delete cascade
);
...

Можно надеятся, что код SQL, созданный компилятором «М», совпадает с тем, что вы бы написали сами. Названия модулей соответствуют названиям схем SQL. Названия типов соответствуют названиям таблиц. AutoNumber соответствует «идентификации» в поле, а ограничение на идентификацию соответствует основному ключевому ограничению на поле. Внутренние типы «M», такие как Integer32 и Text, сопоставляются с соответствующими типами SQL, например, int и nvarchar. Поле коллекции — поле Keywords типа Text* — сопоставляется с другой таблицей, чтобы отнести в эту коллекцию ноль или больше элементов с соответствующими ограничениями внешнего ключа. На рис. 3 показано сопоставление значений.

Рис. 3 Сопоставление типов «M» с кодом SQL

insert into [WixBits].[Packages] ([Product], [Description], [Manufacturer])
 values (@WixBits_Products_Id0, N'A really super pad for notes', @WixBits_Products_Manufacturer0);
declare @WixBits_Packages_Id0 bigint = @@identity;

insert into [WixBits].[Packages_Keywords] ([Item], [Packages_Id])
 values (N'Installer', @WixBits_Packages_Id0);

insert into [WixBits].[Packages_Keywords] ([Item], [Packages_Id])
 values (N'Super', @WixBits_Packages_Id0);

insert into [WixBits].[Packages_Keywords] ([Item], [Packages_Id])
 values (N'Notepad', @WixBits_Packages_Id0);

insert into [WixBits].[Packages_Keywords] ([Item], [Packages_Id])
 values (N'Sample', @WixBits_Packages_Id0);

Пакетирование и развертывание

Выход компилятора «M» по умолчанию — код SQL, который лучше всего использовать в экземпляре SQL Server 2008. По умолчанию этот код SQL пакетируется как один файл сценария SQL.

C:\>m.exe wixbits.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.

C:\>dir wixbits.sql
...
11/22/2008  04:43 PM             2,545 wixbits.sql
...

Можно использовать этот файл сценария для заполнения экземпляра базы данных любым удобным способом, например с помощью sqlcmd.exe или SQL Server Management Studio. Но сценарий SQL содержит гораздо меньше метаданных, чем исходный код «M». Если нужно сохранить эти метаданные, а это стоит сделать, как я сейчас расскажу, то можно выбрать формат пакетирования в виде образа «M», добавив к m.exe флажок командной строки /p:image.

C:\>m.exe /p:image wixbits.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.
C:\>dir wixbits.mx
...
11/22/2008  04:44 PM             9,073 wixbits.mx
...

Файл wixbits.mx — это файл образа «M», содержащий автоматически созданный код SQL, а также манифест и другие метаданные. Так как файл имеет формат OPC (Open Packaging Conventions), для него можно использовать расширение .zip и открывать его как и любой другой файл ZIP. Важнее, однако, то, что файл MX можно использовать для ссылок и развертывания.

Создавая сборку .NET, можно сослаться на эту сборку как часть процесса создания для передачи общедоступных типов и статических экземпляров в программы на основе .NET. Если используются компиляторы командной строки для C# или Visual Basic, можно сослаться на существующие сборки .NET с помощью ключа /r (reference). Подобным образом, если компилируются программы «M», можно использовать ключ /r с компилятором «M» для добавления других типов из образов «M». Для того, чтобы это работало, нужно сперва экспортировать свои типы или экстенты из модуля, на который вы ссылаетесь.

// WixbitsTypes.m 
module WixBits {
    export Product, Package; // export types
    export Products, Packages; // export extents

    type Product {...};
    type Package {...};
    Products : Product*;
    Packages : Package* where item.Product in Products;
}

Затем можно импортировать экспортированные типы и экстенты.

// WixbitsValues.m
module WixBits {
    import WixBits; // bring in exported types and extents
    ...
}

Создав файл образа «M» с результатами экспорта, можно сослаться на него, компилируя программы «M» с результатами импорта (подробнее см. рис. 4).

Рис. 4 Компиляция с импортированными типами и экстентами

C:\>m.exe /p:image /t:Repository WixbitsTypes.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.

C:\>dir WixbitsTypes.mx
...
11/22/2008  05:48 PM            28,332 WixbitsTypes.mx
...

C:\>m.exe /p:image /t:Repository /r:WixbitsTypes.mx WixbitsValues.m
Microsoft (R) "Codename M" Compiler version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.

C:\>dir WixbitsValues.mx
...
11/22/2008  05:50 PM             5,606 WixbitsValues.mx

В дополнение к упаковке типов и экстентов для ссылок в других программах «M» можно развернуть файл образа «M» в экземпляр базы данных SQL Server с помощью служебной программы загрузчика «M», mx.exe, следующим образом.

C:\>mx.exe /db:Repository /i:WixbitsTypes.mx /i:WixbitsValues.mx
Microsoft (R) "Codename M" Command-line Utility version 1.0.0925.0
Copyright (C) Microsoft Corporation. All rights reserved.

Здесь я использую ключ /db для указания, к какой базе данных подключаться, предполагая, что локальный узел — это сервер базы данных, и устанавливаю два файла образов. Я загружаю таблицы в SQL и заполняю их своими значениями, а это значит, что я могу использовать любые технологии доступа к данным для получения их обратно (или для обновления, удаления и добавления новых). В этом случае я использую средство командной строки sqlcmd.

C:\>sqlcmd -d Repository
1> select Name from WixBitx.Products
2> go
Name
----------------
SuperNotepad
(1 rows affected)

Intellipad поддерживает языковые службы «M», включая создание кода SQL, по умолчанию, но поддежки механизма создания образа и ссылок на другие образы нет. Visual Studio, однако, поддерживает эти функции.

Интеграция с Visual Studio

В комплект SDK для платформы «Oslo» встроена поддержка Visual Studio 2008 SP1. После установки комплекта SDK у вас будет шаблон проекта «M», как показано на рис. 5.

По умолчанию к вашему проекту добавляется файл Model1.m. Это обеспечивает те же функции IntelliSense, что в Intellipad. Если нужны дополнительные файлы моделей, можно щелкнуть свой проект правой кнопкой мыши в проводнипе для решений, добавить новый элемент и выбрать шаблон модели «M».

fig05.gif

Рис. 5 Шаблон проекта «M» в Visual Studio 2008

Далее, если нужно сослаться на существуюшие образы «M», это можно сделать, щелкнув проект правой кнопкой мыши и выбрав «Add Reference», а затем указав файл .mx. Например, если нужно создать проект, собирающий значения, с которыми я здесь экспериментировал, и ссылающийся на типы, которыя я показывал, он будет похож на то, что показано на рис. 6.

fig06.gif

Рис. 6 Проект «M» с исходным кодом и ссылкой на файл .mx

При сборке вы увидите ошибки в списке ошибок, как и следовало ожидать, а вывод пойдет в \bin\Debug или \bin\Release (в завимости от собираемой настройки), в том числе файлы .sql и .mx, с которыми можно делать то, что кажется более подходящим (например, выполнить mx.exe на файле вывода .mx). Кроме того, все подобные приемы работают в последней версии CTP Visual Studio 2010.

Процесс сборки в Visual Studio управляется файлом MSBuild с расширением .mproj (см. рис. 7). Это удобно, если нужно использовать файл целей msbuild «Oslo» в файлах собственного проекта.

Рис. 7 Файл MSBuild для проектов «M»

<?xml version="1.0" encoding="utf-8"?>
<Project ...>
  <PropertyGroup>
    <MTarget>Repository</MTarget>
    <MPackageScript>true</MPackageScript>
    <MPackageImage>true</MPackageImage>
    <MTargetsPath Condition="$(MTargetsPath) == ''">
      $(MSBuildExtensionsPath)\Microsoft\M\v1.0</MTargetsPath>
    ...
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="MixbitsValues.m" />
  </ItemGroup>
  <ItemGroup>
    <MReference Include="C:\WixbitsTypes.mx" />
  </ItemGroup>
  <Import Project="$(MTargetsPath)\MProject.targets" />
</Project>

Пример кода

Пример кода, сопровождающий эту статью, — имитация служебной программы установщика репозитория (repinst.exe), которая понимает несколько более насыщенную функциями модель описания файлов MSI, чем та, о которой говорил я. Когда типы и значения, описывающие модели WiX, скомпилированы (с помощью m.exe) и загружены в репозиторий (с помощью mx.exe), при выполнении служебной программы repinst.exe на данных значениях будут прочитаны данные из репозитория, из них будет создан файл MSI, после чего будет запущена установка, позволяющая любому, у кого есть доступ к базе данных, развертывать загруженное таким образом приложение. Это показано на рис. 8.

fig08.gif

Рис. 8 Пример repinst в действии

Я тоже немного поработал над этим примером, в основом переставляя части для наглядности, но основная часть работы (и, соответственно, благодарностей) принадлежит Томасу Делрю (Thomas Delrue), Алехандро Триго (Alejandro Trigo) и Джованни Делла-Либера (Giovanni Della-Libera); они смоделировали WiX, перевели «M» в WiX и создали MSI из данных SQL. Я бы не смог написать эту статью за такое короткое время, если бы не их колоссальный труд. И спасибо Джошу Уильямсу (Josh Williams), Мартину Гаджину (Martin Gudgin) и Джону Доти (John Doty) за создание еще одного целого примера, демонстрирующего функции репозитория, который вы вскоре увидите в Центре разработчика «Oslo».

Крис Селлс (Chris Sells) — руководитель программы в подразделении подключенных систем Майкрософ, где он работает над технологиями разработки приложений следующего поколения. ПОлучить дополнительные сведения о Крисе и его проектах можно на странице sellsbrothers.com.