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' 或 它的依赖项之一。本次大会 由比以下版本更新的运行时构建 当前加载的运行时并且不能 已加载。描述:未处理 期间发生异常 执行当前的网络请求。 请查看堆栈跟踪以了解更多信息 有关错误及其位置的信息 它起源于代码。
异常详细信息:System.BadImageFormatException:无法加载文件或程序集“Ceoimage.Basecamp.XmlSerializers”或其依赖项之一。该程序集是由比当前加载的运行时更新的运行时构建的,无法加载。
我使用 .NET Reflector 查看了 XmlSerializer 的引用,发现它引用了 mscorlib
的 2.0 和 4.0 版本以及 System 的 3.5 和 4.0 版本.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>
I just upgraded a VS 2008 solution containing WinForms, general use libraries, and a web app to VS 2010, but all projects still target .NET 3.5 SP 1. I use this technique to generate XmlSerializers for my general use libraries. The WinForms app runs fine. When my web app tries to run using these libraries that reference the same XmlSerializers, it throws the following:
Server Error in '/WebSubscribers'
Application. Could not load file or
assembly
'Ceoimage.Basecamp.XmlSerializers' or
one of its dependencies. This assembly
is built by a runtime newer than the
currently loaded runtime and cannot be
loaded. Description: An unhandled
exception occurred during the
execution of the current web request.
Please review the stack trace for more
information about the error and where
it originated in the code.Exception Details: System.BadImageFormatException: Could not load file or assembly 'Ceoimage.Basecamp.XmlSerializers' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.
I have looked at the XmlSerializer's references using .NET Reflector and see it references both the 2.0 and 4.0 versions of mscorlib
as well as the 3.5 and 4.0 versions of System.Data.Linq
. Strangely, it only uses the 4.0 version of System.Xml
. That is probably my problem right there.
How can I get the web app to run using these XmlSerializers? When I simply delete those XmlSerializers, the web app runs fine. This is an option, but how can I force MSBUILD to create serializers for a specific version of the CLR?
Here is the MSBuild task I add to project files that forces the creation of the 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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
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 的注册表访问(事件类:Registry,进程名称: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)"
此后不久,当 msbuild 尝试从指定的键加载值时,您可能会看到“NAME NOT FOUND”结果。
从这里应该清楚您需要添加/修改哪些键。
注册表值错误的可能原因有多种。就我而言,Microsoft SDK v7.1 安装的问题意味着注册表项的命名不正确,这已在此处被识别为错误:
http://connect.microsoft.com/ VisualStudio/反馈/详细信息/594338/tfs-2010-build-agent-and-windows-7-1-sdk-targeting-net-3-5-generates-wrong-embedded-resources
MSBuild 4 will (should...) use 3.5 tools to build 3.5 projects. However, it looks like it can't work out where the 3.5 tools are and is using the 4.0 tools. The result is that it is correctly building your 3.5 project (with CLR 2.0.50727 assemblies), but the 4.0 sgen.exe tool is generating Ceoimage.Basecamp.XmlSerializers.dll as a CLR 4.0.30319 assembly.
MSBuild uses the registry to get the path to the v3.5 tools. The MSBuild tasks that require v3.5 SDK tools will fall back to the v4.0 path if the path to the 3.5 tools can't be identified - look at the logic used to set the TargetFrameworkSDKToolsDirectory property in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.NETFramework.props if you're really interested.
You can diagnose and fix possible registry problems as follows:
Install Process Monitor and set up a filter to monitor registry access by msbuild (Event class: Registry, Process Name: msbuild.exe, all types of result)
Run your build
Search Process Monitor for a RegQueryValue access matching "MSBuild\ToolsVersions\4.0\SDK35ToolsPath". Note that this could be be under either "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft" or "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft"
If you have a look at this key in the registry, you'll see that it aliases another registry value, e.g. "$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDK-NetFx35Tools-x86@InstallationFolder)"
Shortly after this, you'll probably see a "NAME NOT FOUND" result as msbuild tries to load the value from the key specified.
It should be clear which keys you need to add / amend from here.
There are a few possible reasons why the registry values are wrong. In my case, an issue with the Microsoft SDK v7.1 installation meant that the registry keys were named incorrectly, which has been identified as a bug here:
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
您是否依赖 4.0 的任何特定内容?
如果您调用 MSBuild 4.0,您将获得 4.0 工具。如果您调用 MSBuild 3.5,您将获得 3.5 工具(这正是您想要的,因为您显然托管在 2.0 CLR 中)。
另一种选择是将 4.0 CLR 放在您的 Web 服务器上。如果未打开,则您的信息流中不应该有任何 4.0 目标内容。
Are you reliant on anything 4.0 specific?
If you invoke MSBuild 4.0, you'll get 4.0 tools. If you invoke MSBuild 3.5, you'll get 3.5 tools (which is what you want as you're clearly hosting in a 2.0 CLR).
The other option is to put the 4.0 CLR on your web server. If that's not open, you shouldnt have any 4.0 targetted stuff in your stream.
我发现我可以显式指定 SGEN 任务的工具路径来使用 3.5 版本,如下所示:
I found I can explicitly specify the SGEN task's tools path to use the 3.5 version, like so: