生成Xml序列化程序集作为构建的一部分

Ada*_*gen 64 c# xml xml-serialization

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

void ReadXml()
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    //...
}
Run Code Online (Sandbox Code Playgroud)

这是一个例外:


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

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


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

如何让visual studio自动生成XML序列化程序集?


更新:生成序列化程序集:打开设置似乎没有做任何事情.

hea*_*vyd 67

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

Microsoft具有文档化的MSBuild属性,允许您禁用该/proxytypes开关并使SGen Task生成序列化程序集,即使程序集中没有代理类型也是如此.

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>
Run Code Online (Sandbox Code Playgroud)

  • (+1)我最初开始沿着所选答案的路径,但发现(至少在MSBuild 4.0中)只是设置$(SGenUseProxyTypes)属性,一行修复! (6认同)
  • 如果可以的话,我会两次投票 (2认同)

fli*_*ubt 56

这是我通过修改.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>
-->
Run Code Online (Sandbox Code Playgroud)

现在我们只插入我们自己的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>
Run Code Online (Sandbox Code Playgroud)

这对我行得通.


Mar*_*rth 28

此问题的其他答案已经提到了项目属性 - >构建 - > 生成序列化程序集设置,但默认情况下,如果项目中存在" XML Web服务代理类型 ",则只会生成程序集.

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

您可以从Visual Studio Output窗口检查此构建任务的结果,然后从Show output from:下拉框中选择Build.你应该看到类似的东西

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 Serializer Generator Tool(Sgen.exe)的各种开关

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

如果您阅读了SGen的文档,他们很清楚Microsoft希望限制此工具的使用.考虑到这个主题的噪音量,很明显微软在记录Visual Studio体验方面做得并不好.甚至还有针对此问题的" 连接反馈"项,响应也不是很好.


小智 9

创建一个新的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" />
Run Code Online (Sandbox Code Playgroud)

其中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>
Run Code Online (Sandbox Code Playgroud)