67

此代码产生 FileNotFoundException,但最终运行没有问题:

void ReadXml()
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    //...
}

这是一个例外:


mscorlib.dll 中出现了“System.IO.FileNotFoundException”类型的第一次机会异常

附加信息:无法加载文件或程序集“MyAssembly.XmlSerializers,Version=1.4.3190.15950,Culture=neutral,PublicKeyToken=null”或其依赖项之一。该系统找不到指定的文件。


如果找不到,框架似乎会自动生成序列化程序集。 我可以使用 sgen.exe 手动生成它,从而缓解异常。

如何让 Visual Studio 自动生成 XML 序列化程序集?


更新: Generate Serialization Assembly: On 设置似乎没有做任何事情。

4

8 回答 8

74

正如 Martin 在他的回答中解释的那样,通过项目属性打开序列化程序集的生成是不够的,因为 SGen 任务正在将/proxytypes开关添加到 sgen.exe 命令行。

Microsoft 有一个记录在案的 MSBuild 属性,它允许您禁用/proxytypes开关并导致 SGen 任务生成序列化程序集,即使程序集中没有代理类型也是如此。

SGenUseProxyTypes

一个布尔值,指示代理类型是否应由 SGen.exe 生成。SGen 目标使用此属性来设置 UseProxyTypes 标志。此属性默认为 true,并且没有 UI 可以更改它。要为非 Web 服务类型生成序列化程序集,请在导入 Microsoft.Common.Targets 或 C#/VB.targets 之前将此属性添加到项目文件并将其设置为 false

正如文档所建议的,您必须手动修改项目文件,但您可以将该SGenUseProxyTypes属性添加到您的配置中以启用生成。您的项目文件配置最终看起来像这样:

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <!-- Snip... -->
    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
    <SGenUseProxyTypes>false</SGenUseProxyTypes>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <!-- Snip... -->
    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
    <SGenUseProxyTypes>false</SGenUseProxyTypes>
  </PropertyGroup>
于 2012-01-10T03:43:51.573 回答
57

这就是我通过修改 .CSPROJ 文件中的 MSBUILD 脚本来设法做到这一点的方法:

首先,将 .CSPROJ 文件作为文件而不是项目打开。滚动到文件底部,直到在 Project 标记关闭之前找到这段注释掉的代码:

<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->

现在我们只需插入我们自己的 AfterBuild 目标来删除我们自己的任何现有 XmlSerializer 和 SGen,如下所示:

<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
   <!-- Delete the file because I can't figure out how to force the SGen task. -->
   <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="$(TargetFrameworkSDKToolsDirectory)"
     Platform="$(Platform)">
      <Output
       TaskParameter="SerializationAssembly"
       ItemName="SerializationAssembly" />
   </SGen>
</Target>

这对我行得通。

于 2008-10-15T14:45:18.973 回答
29

这个问题的其他答案已经提到了 Project Properties->Build-> Generate Serialization Assemblies设置,但默认情况下,只有在项目中有“ XML Web 服务代理类型”时才会生成程序集。

了解 Visual Studio 的确切行为的最佳方法是检查C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727**Microsoft.Common.targets** 文件中的GenerateSerializationAssemblies目标。

您可以从 Visual Studio输出窗口检查此构建任务的结果,然后从显示输出:下拉框中选择构建。你应该看到一些类似的东西

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\sgen.exe /assembly:D:\Temp\LibraryA\obj\Debug\LibraryA.dll / proxytypes /reference:.. /compiler:/ delaysign-LibraryA -> D:\Temp\LibraryA\bin\Debug\LibraryA.dll

这里的关键点是 / proxytypes开关。您可以阅读有关XML 序列化程序生成器工具 (Sgen.exe)的各种开关

如果您熟悉 MSBuild,则可以自定义 GenerateSerializationAssemblies 目标,以便 SGen 任务具有 UseProxyTypes="false" 属性而不是 true,但是您需要承担自定义 Visual Studio / MSBuild 系统的所有相关责任。或者,您可以扩展您的构建过程以手动调用 SGen 而无需 /proxytypes 开关。

如果您阅读 SGen 的文档,他们很清楚 Microsoft 想要限制此工具的使用。考虑到关于这个主题的大量噪音,很明显微软在记录 Visual Studio 体验方面做得并不好。这个问题甚至有一个连接反馈项,但反应不是很好。

于 2008-11-05T06:20:56.880 回答
12

创建一个新的 sgen 任务定义打破了车轮上的苍蝇。只需设置所需的变量以使任务按预期工作。无论如何,微软文档缺少一些重要信息。

预生成序列化程序集的步骤

(部分来自http://msdn.microsoft.com/en-us/library/ff798449.aspx

  1. 在 Visual Studio 2010 的解决方案资源管理器中,右键单击要为其生成序列化程序集的项目,然后单击“卸载项目”。
  2. 在解决方案资源管理器中,右键单击要为其生成序列化程序集的项目,然后单击“编辑 .csproj”。
  3. 在 .csproj 文件中,紧跟在该<TargetFrameworkVersion>v?.?</TargetFrameworkVersion>元素之后,添加以下元素:

    <SGenUseProxyTypes>false</SGenUseProxyTypes> <SGenPlatformTarget>$(Platform)</SGenPlatformTarget>

  4. 在 .csproj 文件中,在每个平台配置中

    例如<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">

    添加以下行:

    <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>

  5. 保存并关闭 .csproj 文件。

  6. 在解决方案资源管理器中,右键单击刚刚编辑的项目,然后单击重新加载项目。

此过程在您的输出文件夹中生成一个名为 .xmlSerializers.dll 的附加程序集。您将需要使用您的解决方案部署此程序集。


解释

默认情况下,SGen 仅适用于为“任何 CPU”生成的代理类型。如果您没有在项目文件中设置相应的变量,就会发生这种情况。

需要 SGenPlatformTarget 才能匹配您的 PlatformTarget。我倾向于认为这是项目模板中的一个错误。为什么 sgen 目标平台与您的项目不同?如果是这样,您将获得运行时异常

0x80131040: 定位程序集的清单定义与程序集引用不匹配

您可以通过分析您的项目文件找到 msbuild 任务定义:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

其中 MSBuildToolsPath 取决于您的<TargetFrameworkVersion> http://msdn.microsoft.com/en-us/library/bb397428.aspx

查看 TargetFrameworkVersion 4.0 的 SGen 任务定义

Windows安装路径\Microsoft.NET\Framework\v4.0.30319\Microsoft.CSharp.targets

要查看 $(SGenPlatformTarget) 等未记录的变量,您可以在项目文件中自由设置

<Target
    Name="GenerateSerializationAssemblies"
    Condition="'$(_SGenGenerateSerializationAssembliesConfig)' == 'On' or ('@(WebReferenceUrl)'!='' and '$(_SGenGenerateSerializationAssembliesConfig)' == 'Auto')"
    DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource"
    Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)"
    Outputs="$(IntermediateOutputPath)$(_SGenDllName)">

    <SGen
        BuildAssemblyName="$(TargetFileName)"
        BuildAssemblyPath="$(IntermediateOutputPath)"
        References="@(ReferencePath)"
        ShouldGenerateSerializer="$(SGenShouldGenerateSerializer)"
        UseProxyTypes="$(SGenUseProxyTypes)"
        KeyContainer="$(KeyContainerName)"
        KeyFile="$(KeyOriginatorFile)"
        DelaySign="$(DelaySign)"
        ToolPath="$(SGenToolPath)"
        SdkToolsPath="$(TargetFrameworkSDKToolsDirectory)"
        EnvironmentVariables="$(SGenEnvironment)"
        SerializationAssembly="$(IntermediateOutputPath)$(_SGenDllName)"
        Platform="$(SGenPlatformTarget)"
        Types="$(SGenSerializationTypes)">
            <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly"/>
    </SGen>
</Target>
于 2013-03-21T02:06:42.133 回答
2

万一其他人在之前一切正常之后突然遇到这个问题:对我来说,这与选项菜单(选项 - >调试)中未选中“启用我的代码(仅限托管)”复选框有关(这是安装 .NET Reflector 后自动关闭)。

编辑:也就是说,当然,这个异常以前发生过,但是当“仅启用我的代码”关闭时,调试助手(如果启用)将在抛出时停止。

于 2010-02-14T10:05:09.863 回答
2

我参加聚会有点晚了,但我发现以前的答案很难处理。具体来说,每当我尝试查看项目的属性时,Visual Studio 都会崩溃。我认为这是因为它不再了解如何读取 csproj 文件。那就是说...

将以下内容添加到您的构建后事件命令行:

"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" "$(TargetPath)" /force

每次为调试或发布构建项目时,这将直接利用 sgen.exe 重新构建 Xml 序列化程序集。

于 2014-08-11T16:01:34.407 回答
1

查看解决方案的属性。在底部的构建选项卡上有一个名为“生成序列化程序集”的下拉菜单

于 2008-09-25T16:12:58.053 回答
1

与大脑备份提供的解决方案略有不同的解决方案可能是直接在您必须使用它的地方指定平台目标,如下所示:

<!-- Check the platform target value and if present use that for a correct *.XmlSerializer.dll platform setup (default is MSIL)-->
<PropertyGroup Condition=" '$(PlatformTarget)'=='' ">
  <SGenPlatform>$(Platform)</SGenPlatform>
</PropertyGroup>
<PropertyGroup Condition=" '$(PlatformTarget)'!='' ">
  <SGenPlatform>$(PlatformTarget)</SGenPlatform>
</PropertyGroup>

<!-- Delete the file because I can't figure out how to force the SGen task. -->
<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)"
  SdkToolsPath="$(TargetFrameworkSDKToolsDirectory)"
  EnvironmentVariables="$(SGenEnvironment)"
  Platform="$(SGenPlatform)">
  <Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
</SGen>
于 2014-01-09T09:15:31.340 回答