Может ли VS.NET 2010/MSBUILD создавать XmlSerializers для .NET 3.5 SP1?

Я только что обновил решение VS 2008, содержащее WinForms, общедоступные библиотеки и веб-приложение для VS 2010, но все проекты по-прежнему нацелены на .NET 3.5 SP 1. Я использую эту технику, чтобы генерировать XmlSerializers для моих общих библиотек. Приложение WinForms работает нормально. Когда мое веб-приложение пытается запустить с использованием этих библиотек, которые ссылаются на те же XmlSerializers, он выдает следующее:

Ошибка сервера в '/WebSubscribers' Заявка. Не удалось загрузить файл или сборка 'Ceoimage.Basecamp.XmlSerializers' или одной из его зависимостей. Эта сборка построена с помощью среды выполнения, более новой, чем в настоящее время загружена среда выполнения и не может быть загружен. Описание: необработанный исключение произошло во время выполнение текущего веб-запроса. Просмотрите трассировку стека информацию об ошибке и он возник из кода.

Сведения об исключении: System.BadImageFormatException: Не удалось загрузить файл или сборку "Ceoimage.Basecamp.XmlSerializers" или одну из его зависимостей. Эта сборка построена с помощью среды выполнения, более новой, чем текущая загруженная среда выполнения, и не может быть загружена.

Я просмотрел ссылки XmlSerializer, используя .NET Reflector и вижу, что он ссылается на версии 2.0 и 4.0 mscorlib, а также версии 3.5 и 4.0 System.Data.Linq. Как ни странно, он использует только версию 4.0 System.Xml. Вероятно, это моя проблема.

Как я могу запустить веб-приложение с помощью этих XmlSerializers? Когда я просто удаляю эти XmlSerializers, веб-приложение работает нормально. Это вариант, но как заставить MSBUILD создавать сериализаторы для определенной версии CLR?

Вот задача MSBuild, которую я добавляю к файлам проекта, которые заставляют создавать XmlSerializers:

<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
 <Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
 <SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="@(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="$(SGenToolPath)">
  <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
 </SGen>
</Target>

Ответ 1

Я обнаружил, что могу явно указать путь к инструментам задач SGEN для использования версии 3.5, например:

<SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="@(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin">

Ответ 2

MSBuild 4 будет (должен...) использовать 3.5 инструмента для создания 3.5 проектов. Однако похоже, что он не может решить, где находятся инструменты 3.5 и использует инструменты 4.0. Результатом является то, что он правильно строит ваш проект 3.5 (с сборками CLR 2.0.50727), но инструмент 4.0 sgen.exe создает Ceoimage.Basecamp.XmlSerializers.dll как сборку CLR 4.0.30319.

MSBuild использует реестр, чтобы получить путь к инструментам v3.5. Задачи MSBuild, требующие инструментов SDK версии 3.5, возвращаются к пути v4.0, если путь к инструментам 3.5 не может быть идентифицирован. Посмотрите на логику, используемую для установки свойства TargetFrameworkSDKToolsDirectory в C:\Windows\Microsoft. NET\Framework\v4.0.30319\Microsoft.NETFramework.props, если вы действительно заинтересованы.

Вы можете диагностировать и исправлять возможные проблемы с реестром следующим образом:

Установите Process Monitor и настройте фильтр для мониторинга доступа к реестру с помощью msbuild (класс события: реестр, имя процесса: msbuild.exe, все типы результатов)

Запустите сборку

Поиск Process Monitor для доступа к RegQueryValue, соответствующего "MSBuild\ToolsVersions\4.0\SDK35ToolsPath". Обратите внимание, что это может быть как "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft", так и "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft"

Если вы посмотрите на этот ключ в реестре, вы увидите, что он псевдонизирует другое значение реестра, например. "$ (Реестр: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDK\Windows\v7.1\WinSDK-NetFx35Tools-x86 @InstallationFolder)" Вскоре после этого вы, вероятно, увидите результат "NAME NOT FOUND", так как msbuild пытается загрузить значение из указанного ключа.

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

Существует несколько возможных причин неправильного значения реестра. В моем случае проблема с установкой Microsoft SDK v7.1 означала, что ключи реестра были названы неправильно, что было определено как ошибка здесь:

http://connect.microsoft.com/VisualStudio/feedback/details/594338/tfs-2010-build-agent-and-windows-7-1-sdk-targeting-net-3-5-generates-wrong-embedded-resources

Ответ 3

Вы полагаетесь на что-то конкретное 4.0?

Если вы вызываете MSBuild 4.0, вы получите 4.0 инструментов. Если вы вызовете MSBuild 3.5, вы получите 3.5 инструмента (именно это вы хотите, поскольку вы четко размещаете в среде CLR 2.0).

Другой вариант - разместить 4.0 CLR на вашем веб-сервере. Если это не открыто, в вашем потоке не должно быть никаких целевых объектов размером 4.0.