代码之家  ›  专栏  ›  技术社区  ›  Adam Tegen

作为生成的一部分生成XML序列化程序集

  •  62
  • Adam Tegen  · 技术社区  · 16 年前

    此代码生成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序列化程序集?


    更新:设置上的生成序列化程序集似乎没有执行任何操作。

    8 回复  |  直到 10 年前
        1
  •  56
  •   Justin Dearing    12 年前

    这是我如何通过修改.csproj文件中的msbuild脚本来实现的:

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

    <!-- 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>
    

    这对我很有用。

        2
  •  65
  •   Community omersem    7 年前

    正如马丁在书中解释的那样 his answer ,通过项目属性打开序列化程序集的生成是不够的,因为sgen任务正在添加 /proxytypes 切换到sgen.exe命令行。

    微软有 documented MSBuild property 它允许您禁用 /类型 切换并使sgen任务生成序列化程序集,即使程序集中没有代理类型。

    sgenusproxytypes公司

    一个布尔值,指示代理类型 应该由sgen.exe生成。sgen目标使用此属性 设置useproxytypes标志。此属性默认为true,并且 没有用于更改此内容的用户界面。为生成序列化程序集 非WebService类型,将此属性添加到项目文件并设置它 在导入microsoft.common.targets或 C/V/B目标

    正如文档所建议的,您必须手工修改项目文件,但是您可以添加 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>
    
        3
  •  28
  •   Martin Hollingsworth    16 年前

    此问题的其他答案已提到项目属性->内部版本-> 生成序列化程序集 设置,但默认情况下,仅当存在 XML Web服务代理类型 “在项目中。

    理解Visual Studio的确切行为的最佳方法是检查 生成序列化程序集 目标位于c:\windows\microsoft.net\framework\v2.0.50727**microsoft.common.targets**文件中。

    可以从Visual Studio检查此生成任务的结果 产量 窗口并选择 建造 显示的输出来自 :下拉框。你应该看到一些沿着

    C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\sgen.exe/assembly:D:\temp\librarya\obj\debug\librarya.dll/ 丙型 参考文献/编译器:/delaysign- 库->d:\temp\librarya\bin\debug\librarya.dll

    关键是/ 丙型 开关。您可以阅读有关 XML Serializer Generator Tool (Sgen.exe)

    如果您熟悉msbuild,则可以自定义generateserializationassembly目标,以便sgen任务具有useproxytypes=“false”而不是true的属性,但是 然后,您需要承担定制Visual Studio/MSBuild系统的所有相关责任。或者,您可以扩展构建过程,在不使用/proxytypes开关的情况下手动调用sgen。

    如果您阅读了SGen的文档,他们会非常清楚地看到,微软希望限制使用该工具。考虑到这个话题的噪音,很明显微软在记录Visual Studio体验方面做得不好。甚至还有一个 Connect Feedback 这个问题的项目和响应不是很好。

        4
  •  9
  •   brain backup    11 年前

    创建一个新的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匹配。我倾向于认为这是项目模板中的一个bug。为什么SGEN目标平台与您的项目不同?如果是这样,您将得到一个运行时异常

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

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

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

    msbuildtoolspath依赖于 <TargetFrameworkVersion> http://msdn.microsoft.com/en-us/library/bb397428.aspx

    从中查找TargetframeworkVersion4.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>
    
        5
  •  2
  •   joniba    14 年前

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

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

        6
  •  2
  •   mcfea    10 年前

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

    将以下内容添加到生成后事件命令行:

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

    这将直接利用sgen.exe在每次构建用于调试或发布的项目时重建XML序列化程序集。

        7
  •  1
  •   Darren Kopp    16 年前

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

        8
  •  1
  •   Community omersem    7 年前

    brain backup 可以直接指定平台目标,在这里您必须这样使用它:

    <!-- 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>