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

Я только что обновил решение VS 2008, содержащее WinForms, библиотеки общего пользования и веб-приложение, до VS 2010, но все проекты по-прежнему ориентированы на .NET 3.5 SP 1. Я использую этот метод для создания XmlSerializer для моих библиотек общего назначения. Приложение 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. Как ни странно, он использует только версию System.Xml 4.0. Это, наверное, моя проблема прямо здесь.

Как я могу запустить веб-приложение с помощью этих XmlSerializer? Когда я просто удаляю эти 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>

person flipdoubt    schedule 23.08.2010    source источник
comment
вы должны добавить это изменение в качестве ответа, чтобы мы могли проголосовать за него, это кажется лучшим решением :)   -  person Lucas    schedule 25.08.2010


Ответы (3)


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

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

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

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

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

Монитор процесса поиска для соответствия доступа RegQueryValue "MSBuild \ ToolsVersions \ 4.0 \ SDK35ToolsPath". Обратите внимание, что это может быть либо «HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft», либо «HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft».

Если вы посмотрите на этот ключ в реестре, вы увидите, что он является псевдонимом другого значения реестра, например «$ (Реестр: HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Microsoft SDKs \ Windows \ v7.1 \ WinSDK-NetFx35Tools-x86 @ InstallationFolder)» Вскоре после этого вы, вероятно, увидите результат «ИМЯ НЕ НАЙДЕНО», когда 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

person Dan Malcolm    schedule 18.04.2011
comment
Спасибо за этот ответ. Я комбинирую это с stackoverflow.com/a/2739132/281084, чтобы решить свою проблему. - person Grimace of Despair; 02.05.2013

Вы полагаетесь на что-нибудь конкретное для 4.0?

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

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

person Ruben Bartelink    schedule 24.08.2010
comment
Я только что проверил один из своих проектов и обнаружил, что он ссылается только на сборки фреймворка 2.0 и 3.5. Однако я заметил одну вещь: свойство Specific Version каждого фреймворка ссылается на false. Когда я выгружаю проект и заглядываю в файл .CSPROJ, тег свойства упоминает инструменты 4.0 следующим образом: <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> Когда я меняю ToolsVersion на 3.5, VS 2010 преобразует проект и возвращает значение 4.0. - person flipdoubt; 24.08.2010
comment
@flipdoubt: Версия инструментов VS2010 forcing 4.0 - известная проблема (выполните поиск). проблема здесь в том, что импортируемая задача SGen - это задача sgen 4.0, которая по умолчанию будет использовать SGen.exe 4.0. Возможно, переопределение ToolPath для работы mioght 3.5 SGen. - person Ruben Bartelink; 24.08.2010
comment
А потом я посмотрел на вашу правку. Я думаю, что это лучшее решение, учитывая, что запуск ваших проектов ToolsVersion 4.0 через MSBuild 3.5 не будет долгосрочным решением. - person Ruben Bartelink; 24.08.2010

Я обнаружил, что могу явно указать путь к инструментам задачи 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">
person flipdoubt    schedule 25.08.2010
comment
Вы меняете целевой файл или каким-то образом модифицируете файлы проекта? Я не знаю, как применить это к моей среде ... - person John Leidegren; 09.11.2012
comment
Это было давно, но я почти уверен, что редактировал файл CSPROJ напрямую. - person flipdoubt; 11.11.2012