Search code examples
c#xmlxml-serialization

Generating an Xml Serialization assembly as part of my build


This code produces a FileNotFoundException, but ultimately runs without issue:

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

Here is the exception:


A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll

Additional information: Could not load file or assembly 'MyAssembly.XmlSerializers, Version=1.4.3190.15950, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.


It appears that the framework automatically generates the serialization assembly if it isn't found. I can generate it manually using sgen.exe, which alleviates the exception.

How do I get visual studio to generate the XML Serialization assembly automatically?


Update: The Generate Serialization Assembly: On setting doesn't appear to do anything.


Solution

  • This is how I managed to do it by modifying the MSBUILD script in my .CSPROJ file:

    First, open your .CSPROJ file as a file rather than as a project. Scroll to the bottom of the file until you find this commented out code, just before the close of the Project tag:

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

    Now we just insert our own AfterBuild target to delete any existing XmlSerializer and SGen our own, like so:

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

    That works for me.