我刚刚将包含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>
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-资源
您是否依赖于任何4.0特定的东西?
如果您调用MSBuild 4.0,您将获得4.0工具。如果您调用MSBuild 3.5,您将获得3.5个工具(这是您想要的,因为您在2.0 CLR中明显托管)。
另一种选择是将4.0 CLR放在Web服务器上。如果没有打开,你的流中不应该有任何4.0目标内容。
我发现我可以明确指定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">