问题 VS.NET 2010 / MSBUILD可以为.NET 3.5 SP1生成XmlSerializers吗?


我刚刚将包含WinForms,通用库和Web应用程序的VS 2008解决方案升级到VS 2010,但所有项目仍然针对.NET 3.5 SP 1.我使用 这种技术 为我的一般用途库生成XmlSerializers。 WinForms应用程序运行正常。当我的Web应用程序尝试使用引用相同XmlSerializers的这些库运行时,它会抛出以下内容:

'/ WebSubscribers'中的服务器错误   应用。无法加载文件或   部件   'Ceoimage.Basecamp.XmlSerializers'或   其中一个依赖项。这个集会   由比运行时更新的运行时构建   目前加载运行时并不能   加载。描述:未处理   期间发生了异常   执行当前的Web请求。   请查看堆栈跟踪了解更多信息   有关错误的信息和位置   它起源于代码。

异常详细信息: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运行Web应用程序?当我只是删除那些XmlSerializers时,Web应用程序运行正常。这是一个选项,但是如何强制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>

8367
2017-08-23 15:45


起源

你应该添加该编辑作为答案,以便我们可以投票,它似乎是最好的解决方案:) - Lucas


答案:


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工具的路径。如果无法识别3.5工具的路径,则需要v3.5 SDK工具的MSBuild任务将回退到v4.0路径 - 查看用于在C:\ Windows \ Microsoft中设置TargetFrameworkSDKToolsDirectory属性的逻辑。 NET \ Framework \ v4.0.30319 \ Microsoft.NETFramework.props如果你真的很感兴趣。

您可以按如下方式诊断和修复可能的注册表问题:

安装Process Monitor并设置一个过滤器来监视msbuild的注册表访问(事件类:注册表,进程名称:msbuild.exe,所有类型的结果)

运行你的构建

搜索Process Monitor以查找与“MSBuild \ ToolsVersions \ 4.0 \ SDK35ToolsPath”匹配的RegQueryValue访问。请注意,这可能位于“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)” 在此之后不久,您可能会看到“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-资源


8
2018-04-18 12:34



+1解释 - remi bourgarel
谢谢你的回答。我把它与之结合起来 stackoverflow.com/a/2739132/281084 解决我的问题 - Grimace of Despair


您是否依赖于任何4.0特定的东西?

如果您调用MSBuild 4.0,您将获得4.0工具。如果您调用MSBuild 3.5,您将获得3.5个工具(这是您想要的,因为您在2.0 CLR中明显托管)。

另一种选择是将4.0 CLR放在Web服务器上。如果没有打开,你的流中不应该有任何4.0目标内容。


2
2017-08-24 08:40



我刚检查了一个项目,发现它只引用了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。 - flipdoubt
@flipdoubt:VS2010强制4.0 toolversion是一个已知问题(有搜索)。这里的问题是导入的SGen任务是4.0 sgen任务,默认为4.0 SGen.exe或许将ToolPath覆盖到3.5 SGen mioght工作。 - Ruben Bartelink
然后我查看了你的编辑。我认为这是最好的解决方案,因为通过MSBuild 3.5运行你的ToolsVersion 4.0项目不是一个长期的解决方案 - Ruben Bartelink


我发现我可以明确指定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
2017-08-25 14:55



您是在更改目标文件还是在修改项目文件?我不知道如何将它应用到我的环境...... - John Leidegren
这是很久以前的事了,但我很确定我直接编辑了CSPROJ文件。 - flipdoubt