Тэги

Silverlight (36) WPF (10) IIS (7) Visual Studio (7) SharePoint (6) .Net Framework (5) ODP.NET (5) ASP.NET (4) C# (4) common (4) Network Settings (3) JavaScript (2) MS Office (2) Resharper (2) WCF (2) WEB (2) XPath (2) XSLT (2) ADO.NET (1) APEX (1) CMD (1) CSS (1) EF (1) HTML (1) Hardware bugs (1) Java (1) MS SQL (1) Oracle (1) PDF (1) Version Control (1) XAML (1)

среда, 16 марта 2011 г.

Ускорение компиляции Visual Studio Solution методом "Copy Local = False".

Обычное исключение из компиляции не изменяемых проектов через Build -> Configuration Manager (колонка Build напротив каждого проекта) не единственный подход для ускорения компиляции в Visual Studio (VS).
Другой способ, строится на том, что нужно отключить поведение Visual Studio по умолчанию, когда VS копирует сборки проектов, в проекты которые ссылаются на первые.

Почему и как:
Если проект A ссылается на проект B, то проект B компилируется первым.
По умолчанию, сборка проекта B дублируется и кладется вместе со сборкой проекта A.
Подход предлагает отключить копирование сборок проектов в Solution с помощью установки свойства референса на сборку Copy Local равным False, а также помещать все сборки в общую папку.

Когда применять:
Я бы использовал только для крайне больших солюшенов, когда более 5 - 10 проектов. Думаю, не стоить без нужды запутывать разработку.

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

Внимание!
Не приступайте к реализации, не изучив пункт Исключения после этих шагов.

  1. Если вам надо будет добавлять референсы на другие проекты внутри solution, то не важно через что вы будете это делать в окне Add Reference, через вкладку Projects или через вкладку Browse. Только не забывайте пройти все пункты этой инструкции для каждого нового проекта.

  2. Настройте общую папку(и) для сборок внутри Solution.В свойствах каждого проекта выберите вкладку Build.
    Далее зададим путь до общей папки через поле Output path, но сначала обратите внимание, что вверху вкладки Build есть выпадающий список Configuration, где выбирается конфигурация компиляции (обычно Release или Debug или какая-то ваша кастомная, если была создана).Если вы хотите задать одинаковую папку для всех конфигураций компиляции, то выберите в этом списке "All configurations" и задайте значение в поле Output path, например такое "..\bin\", тогда в корне проекта у вас появится папка bin.Если же вам для каждой конфигурации нужно задать отдельную папку, то задайте путь в поле Output path для каждой конфигурации в списке Configurations, кроме значения "All configurations". Например для Release можно задать "..\bin\Release\", а для Debug "..\bin\Debug\".Внимание!
    У Web-проектов ASP.NET папка bin может находиться только внутри корневой папки Web-проекта.

    Внимание!
    Если у вас есть проекты, расположены не в корне папки солюшена, то соответственно, поправьте путь для таких проектов.
    Например может понадобится написать не "..\bin\", а "..\..\bin\".

  3. Проверьте и настройте, если понадобится, вручную порядок компиляции.
    Мне еще не приходилось воспользоваться этим пунктом, но по мнению Patrick Smacchia (см. в конце) это может понадобится.
    Будьте предельно внимательны, иначе вы можете получать неприятные ошибки.
    Порядок компиляции можно посмотреть из Solution Explorer вызвав из контекстного меню любого проекта или солюшена пункт Project Build Order.
    Настроить порядок можно там же через пункт Project Dependencies.

  4. Задайте Copy Local равным False!
    Во всех проектах, в свойствах каждого референса на проект внутри Solution задайте Copy Local = False.
    Для этого в Solution Explorer выберите проект, разверните в нем вкладку References, там и лежат референсы.

  5. В конце, чтоб подхватились новые референсы (сборки) в зависимых проектах, выполните Rebuild Solution!
    При ошибке отсутствия dll выполните ребуилд еще раз.

  6. Можете удалить все ваши старые папки bin в каждом проекте, т.к. они больше не используются.
    Но аккуратнее, т.к. у некоторых разработчиков в них могут лежат сторонние уникальные сборки, которых нигде больше нет (на случай когда контроль версий недоступен).


Исключения.

  1. Случай, когда у вас Solution, в котором несколько корневых проектов!
    Смысл тут такой - для каждого звена (tier) нужна своя общая папка.
    Т.е. для каждого "корневого" проекта должна быть своя общая папка.
    Например, у вас в солюшене, помимо проектов относящихся к Silverlight, есть и другие проекты (обычно ASP.NET), в этом случае для Silverlight создавайте свою отдельную общую папку.
    Понятно, что нет смысла перемешивать в одной папке DLL от ASP.NET и Silverlight.

  2. Случай, когда у вас несколько корневых проектов, но они используют общую сборку одного проекта в вашем Solution.
    Лучше сразу попытаться избавиться от этой ситуации или призадуматься, стоит ли применять описанный в статье подход, если общих сборок много. Например такое можно встретить, если у вас в проекте несколько сайтов ASP.NET.К этому случаю не относится Solution в котором одновременно Silverlight и ASP.NET, т.к. у них разные версии .NET Framework и они обычно не пересекаются по сборкам (ну или делайте кросс-компиляционные проекты).
    В случае WCF этого, обычно, тоже можно избежать.Тут вы должны подойти творчески.
    Во первых теперь только для одного "корневого" проекта можно оставить Copy Local равным False в свойствах референса на разделяемый проект (сборку).
    Делайте с расчетом на то, что те проекты, в которых пришлось оставить Copy Local равным True, больше подходят под категорию проектов, которые можно исключить из компиляции (Build -> Configuration Manager, колонка Build напротив каждого проекта).
    Либо можно закрыть глаза на наличие не нужных сборок и exe и запихать таки всё в одну папку. Тогда при развертывании, у вас будут на звеньях (tier) не относящиеся к звену компоненты. Фу какая гадость :) . Хотя это решается скриптом подготовки релиза в Post Build Event. Но это уже муторно.


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

В статье Patrick Smacchia Partitioning Your Code Base Through .NET Assemblies and Visual Studio Projects, где я это подсмотрел, говорится о подходе к ускорению в целом, а не только с использованием метода Copy Local False.

понедельник, 14 марта 2011 г.

Способы слияния сборок .NET Framework.



Merging assemblies приятная задачка, позволяющая на выходе получить один исполняемый файл или одну dll.

Слияние (мерджинг) сборок можно выполнить двумя основными способами:

  1. Использовать утилиту слияния.
    Самая распространенная и бесплатная утилита, это утилита командной строки ILMerge.
    Чтоб ее использовать, например, бросьте в папку главного проекта ILMerge.exe, потом зайдите в свойства этого проекта и в Buil Events пропишите в поле Post-buid events command line вызов этой утилиты, например так:
    "$(ProjectDir)ilmerge" /out:"$(ProjectDir)!Output\$(TargetFileName)" "$(TargetPath)" "$(TargetDir)Prived.Midved.dll" "$(TargetDir)WindowsProcessManager.dll" del "$(ProjectDir)!Output\$(ProjectName).pdb"
    Где ключ /out указывает куда класть не по умолчанию готовую сборку или экзешник. В нашем случае это будет папка !Output в корне проекта.
    Потом перечисляются сборки, который нужно запихнуть в итоговый файл.
    Команда del в конце, используется для удаления файла ".pdb".
    Можно изловчиться и сделать так, чтоб слияние отрабатывало только в случае компиляции не для дебаггинга, но я это делал через свой экзешник передавая в командной строке $(ConfigurationName).

    Мнимый недостаток ILMerge то, что сборки теряют свою идентичность - имя, версию, культуру, публичный ключ.

  2. Загрузка сборок в рунтайме по требованию.
    Это более гибкий метод, но также и более подверженный поздним ошибкам.
    Используется внедрение нужных сборок, как ресурсов в основную сборку и потом реагирование на событие AppDomain.CurrentDomain.AssemblyResolve для извлечения сборок из ресурса и загрузки в рантайме.
    Я вам очень советую в случае использования этого способа написать тест, который при старте приложения вызывает по одному типу (методу, члену) из каждой используемой сборки в ресурсе.

Некоторый средства обфускации тоже имеют функцию слияния (точно не помню).

воскресенье, 13 марта 2011 г.

Visual Studio The Watch window bug for XPath.

Ну надо же, как приятно снова встретить старинный баг, плавно перекачевавшый теперь уже в Visual Studio 2010.

Окно Watch не умеет интерпретировать XPath выражения содержащие < и подобрые вещи, например выражение
ServiceRow[position() <= $Count]
в окне Watch отобразиться как недопустимое.

Полностью в XSLT файле это выглядит вот так:
<xsl:variable name="MyVar" select="ServiceRow[position() &lt;= $Count]"/>

В тоже время то, что будет работать в Watch, нельзя вставить в XSLT / XPath, т.к. является некорректным XML:
ServiceRow[position() <= $Count]

Так что не профукайте ваше время впустую.

Лично мой давний запрос, по поводу этого бага, тех. поддержка Microsoft плавненько слила. :)

IIS 6.0 не выгружает файлы с расширением .exe

Если IIS 6.0 не выгружает файлы с расширением .exe, то проверьте, чтоб в настройках каталога / сайта у вас НЕ стояло "Execute permissions" равное "Scripts and Executables". В этом случае еще ошибка "HTTP Error 404" будет отображаться.

Бизнес сказал: С Индией дружить.

На днях, встретил замерзшего индийского программиста в районе Ситроникса (Москва, метро Новослободская).
У Ситроникса давние терки с Индией, поэтому я уверенно направил человека туда.
При этом добрый индус с уверенностью сказал, что знает что такое МТС и Форис (для тех, кто в курсе). Оказалось соврал :) .

Выяснилось, что человек шел устраиваться на работу в друге место и я самолично проводил его в евоную контору.

Показательно, что конторка, видимо, маленькая.

XSLT и XPath баг в MSXML 4.0.

Нашел баг XSLT и XPath в MSXML 4. Видимо в версиях ниже он тоже есть.

Если в XSLT-переменную xsl:variable положить набор нод, полученный с помощью XPath выражения preceding-sibling, то набор строк (Node Set) в этой переменной будет храниться не в том порядке, в котором он представлен в XML.
Вроде, порядок нод будет обратный тогда.

При этом, если перебирать Node Set напрямую в xsl:for-each, без присвоения набора в переменную xsl:variable, то все будет работать правильно. Утверждать не стану, т.к. уже не помню точно, но вроде это так.

Получается в MSXML 4, preceding-sibling можно использовать только для получения количества элементов в наборе нод или для прямого перебора, но не для выборки элементов в переменную.

Проиллюстрирую баг кодом.
В следующей переменной FirstSecondThirdTables.Rows получим набор элементов ServiceRow, лежащих до ноды из переменной $FourthTable.Rows.First.
Но порядок элементов в ней будет не такой, какой он в XML:
<xsl:variable name="FirstSecondThirdTables.Rows" select="$FourthTable.Rows.First/preceding-sibling::ServiceRow"/>
Вот как обойти этот баг:
<!-- it3xl.ru: Сначала получим количество нужных нод лежащих до граничной ноды -->
<xsl:variable name="FirstSecondThirdTables.RowsCount" select="count($FourthTable.Rows.First/preceding-sibling::ServiceRow)"/>
<!-- it3xl.ru: Теперь применим стандартный фильтр по position(). -->
<xsl:variable name="FirstSecondThirdTables.Rows" select="ServiceRow[position() &lt;= $FirstSecondThirdTables.RowsCount]"/>


! Обратите внимание, что Visual Studio с 2005-й версии, да и MS SQL, уже давно используют MSXML 6, поэтому вы можете заметить баг только на промышленной среде.

Чтобы быстро проверить на этот баг в разработческой среде нужен скрипт, который выполняет XSLT преобразования именно через MSXML 4.
Я такой батничек или JS-скрипт затерял, поэтому MSDN вам в помощь для написания этого скрипта. Можно начать отсюда http://msdn.microsoft.com/en-us/library/ms757837(VS.85).aspx.

Мой большой друг спросил меня по этому поводу: "Ребята из Рэдмонда опять что-то отчебучили?"
Хотел бы я там с ними тоже поотчебучивать :)
Вот только Service Pack на это надо было бы уже давно поставить.