Monday, September 29, 2008

Entity Framework + NAnt - трудности с включением файлов модели в сборку

Вдогонку своему предыдущему посту про миграцию на .NET 3.5 SP1 пишу еще один, может, кому полезно будет. Еще одна беда подкралась внезапно, со стороны компиляции метаданных контекста EF в библиотеку. Дело в том, что у нас есть автобилды, построенные на Cruise Control + NAnt. Как вы сами, наверно, уже догадались, если NAnt'у не сказать, чтобы он билдил csdl, msl и ssdl в сборку, он сам не догадается. В принципе, ничего особенного, даже поста отдельного не заслуживает, однако здесь есть одна засада.

Дело в том, что раньше процессом разбивания файла edmx на три файла метаданных занимался специальный exe-файл, который назывался EdmxDeploy.exe, который по умолчанию не включал файлы метаданных в сборку, это нужно было делать отдельно. Так мы и жили, кто хотел – работал с файлами на диске, остальные – с ресурсами. Теперь же сборкой занимается специальный таск MSBuild, который лежит глубоко внутри и по умолчанию билдит метаданные в сборку. Мы переписали все строки соединения на ресурсы и думали, что дешево отделались. Не получилось: упал серверный билд. Причем, причина падения понятна – в сборке просто нет ресурсов с метаданными, но вот как их туда добавить, если у нас лишь edmx-файл? Как я ни пытался настроить билд edmx-файла, чтобы он и в сборку данные клал, и три файла метаданных мне на диск генерировал – ничего не получалось. Старый EdmxDeploy.exe разработчики с диска уже снесли – он вроде как не нужен. С горя уже полез изучать, как извне запустить MSBuild и получить нужные мне файлы метаданных отдельно, чтобы потом через <resources> добавить их в сборочный процесс NAnt'а. Однако снова спас гугл. В процессе поиска утилит случайно наткнулся на утилиту EdmGen2, которая, в отличие от EdmGen как раз и занимается тем, что умеет делить и собирать edmx.

У этой замечательной тулы есть несколько параметров, которые позволяют генерировать csdl, msl и ssdl по edmx, наоборот, валидировать edmx-модель, а также генерировать edmx-модель по базе и потом код по этой модели. Ну, и на закуску, эта тула поставляется с исходниками, так что вы можете все посмотреть и исправить в случае необходимости сами.

Все, что остается в нашем случае – это лишь добавить код генерации нужных нам файлов в postbuild-скрипт и добавить сгенерированные файлы в nant-скрипт.

Postbuild-скрипт:

rem Post-build Event Command Line:
rem "$(ProjectDir)postbuild.cmd" "$(ProjectDir)"

@echo off
cd "%1"
%WINDIR%\system32\xcopy "%1Model\Model.edmx" "%1EntitySchema\" /s /r /y

cd "%1EntitySchema"
EdmGen2.exe /FromEdmx CCF.edmx

Кусок nant-скрипта:

<target name="build">
    <csc ...>
        ...
        <resources prefix="Model">
            <include name="EntitySchema/Model.csdl" />
            <include name="EntitySchema/Model.ssdl" />
            <include name="EntitySchema/Model.msl" />
        </resources>
    </csc>
</target>

6 comments:

  1. Вопрос: Чем Cruise Control и MSBuild'а не хватает для автоматизации сборки, у нас они отлично вместе работают? А раньше мы NAnt'ом пользовались :-)...

    ReplyDelete
  2. Cruise Control и MSBuild отлично работают вместе и я подумываю над переходом на MSBuild :) Просто у нас исторически сложилось, что мы юзаем именно пару Cruise Control/NAnt. Вот и паримся :)

    ReplyDelete
  3. Саш, мы с тобой обсуждали как делается подобная интеграция. Обновляй пост :)
    ЗЫ. Давайте не путать теплое с мягким :-) CC.Net не подразумевает nant или msbuild. CC.Net так же отлично интегрейтится со многими вещами (CC.Net confluence)

    ReplyDelete
  4. А никто и не утверждает, что CC.Net может интегрироваться лишь с одним или вторым :) Я просто описал случай с NAnt, а Толик спросил про MSBuild - вот и все. Обновлять пост, думаю, не стоит, я лучше здесь опишу второй вариант.

    Как альтернатива, можно попытаться дать на вход NAnt'у sln-файл, у него даже тег специальный есть - <solution>, однако я не уверен, что это сработает для .NET 3.5 или .NET 3.5 SP1 (появились специфические типы проектов). Это лучше уже уточнить на сайте NAnt и, если появилась подходящая версия - скачать оттуда.

    ReplyDelete
  5. Хм, есть решение о котором ты дипломатично умолчал :)

    на момент когда я делал подобное, тег solution не воспринимал даже vs2005 формат.В stdout так и писал - не буду билдить ваш солюшн, он 2005й. Тег <solution> отлично работал для vs2003.

    Поэтому есть определенного рода сомнения, что через тег <solution> ты сможешь билдить 2008 проекты.

    Насколько я помню, мы использовали нантовский таргет, который в консоли вызывал msbuild -b "solutionfile.sln".
    Решение сомнительное с эстетической стороны :) Но работает лучше, чем править build script для каждого embedded файла ;)

    ReplyDelete
  6. А, ты про этот вариант :) Я думал, ты как раз про упомянутый мной говорил. Такой способ тоже работает и имеет право на жизнь.

    Спасибо, что напомнил :)

    ReplyDelete