Monday, February 05, 2007

VS2005 - When SGEN Doesn't Work...

One of the features I was looking forward to making use of in .NET 2.0 was that of pre-generating the xml serialization assemblies, such as described in this post.

Using the sgen.exe tool is fairly straightforward, and there is an <SGen> MSBuild task for this purpose as well. However there is also one other option which not many people seem to have discussed the problem with that I could find.

If you look on the Build tab for your C# project you will see a "Generate serialization assembly" option with a badly aligned-combo box and a mysterious default option of "Auto" that is not described in the MSDN help - more attention to detail by Microsoft in VS2005.


Switching this combo to "On" and compiling a bunch of different projects I found each time that no xml serializer assembly was being produced. This had me rather irritated, and I know of others who had the same problem but no mention of why.

By looking at the MSBuild output with verbose detail you see a first hint as to what is going on:

Assembly 'C:\Foo\obj\Debug\Foo.dll' does not contain any types that can be serialized using XmlSerializer. Please use /verbose switch for more information.

How come? I can run sgen.exe from the command line on the same assembly and that works just fine producing output. Ok, lets take the command from the MSBuild output for sgen.exe and add /verbose to it...

Assembly 'C:\Foo\obj\Debug\Foo.dll' does not contain any types that can be serialized using XmlSerializer. Please use /verbose switch for more information.

WTF? I did add /verbose - fat lot of good it did me. What else is on that sgen.exe command line...

...sgen.exe /assembly:C:\Foo\obj\Debug\Foo.dll /proxytypes /reference:...

Aha - that /proxytypes option looks a bit interesting. The description in the MSDN documentation is "Generates serialization code only for the XML Web service proxy types."

An explanation at last - the property page option is effectively useless unless you are using web services. If you have other uses of xml serialization like many of us do then you have to resort to post-build tasks or scripting sgen.exe externally. All Microsoft had to do was change the combobox options to something like "Off", "ProxyTypes", "All" and this feature would have been far more useful.

Incidentally I also found if you remove the /proxytypes option the /verbose option starts working - quality.

[Update: 17th March 2006]
I should have posted the actual workaround I implemented, which I will now for at least my own purposes of reusing it. By adding the below extract into your .csproj file this will ensure that every time you compile the xml serialization assembly is regenerated for non web proxy classes.

<!-- Grant - this bodge is necessary as Microsoft screwed up the xml serializer
generation by limiting it to only web proxy classes.
The one line change from the equivalent
target in Microsoft.Common.targets is to set UseProxyTypes to false.
-->
<Target Name="GenerateSerializationAssembliesForAllTypes"
DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource"
Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)"
Outputs="$(OutputPath)$(_SGenDllName)">
<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>
<!-- <Target Name="BeforeBuild">
</Target> -->
<Target Name="AfterBuild"
DependsOnTargets="GenerateSerializationAssembliesForAllTypes">
</Target>

11 Comments:

At March 10, 2007 10:43 pm, Anonymous Anonymous said...

Champion work! , and very timely too.

Another KiwiDude

 
At March 19, 2007 10:36 am, Blogger Ian Davis said...

Thanks for posting the workaround. It works perfectly!

 
At April 12, 2007 5:20 pm, Anonymous Anonymous said...

!10X help me a lot!

 
At December 17, 2007 1:51 pm, Anonymous Anonymous said...

Sadly, this workaround doesn't work with TFS Build...

There is some files moving which are involved before the command is invoked.

 
At October 07, 2008 12:05 pm, Anonymous Anonymous said...

You can also override the existing target by giving it the same name. Doing so will include the generation in the "normal" build process, so you don't have to add it to "AfterBuild".

 
At October 05, 2009 3:46 pm, Blogger Unknown said...

how can you exclude all unvisited code from coverage results. Please help...

 
At October 05, 2009 8:13 pm, Blogger kiwidude said...

You should really ask on the ncover.com forums. In the gui it is just "Hide unvisited" (Alt+ 2), and in the NAnt/MSBuild tasks you can do the same using the "Filter" property.

 
At February 12, 2010 6:21 pm, Anonymous Anonymous said...

In newer versions of VisualStudio you just need to set one property in the project to achieve the same behavior (no UI unfortunately):
false

 
At February 12, 2010 6:23 pm, Anonymous Anonymous said...

The property is <SGenUseProxyTypes>false</SGenUseProxyTypes>

 
At March 19, 2010 11:40 pm, Anonymous Anonymous said...

Great Job. Worked great.

 
At November 19, 2010 8:58 am, Anonymous viagra online said...

I, of course, a newcomer to this blog, but the author does not agree

 

Post a Comment

<< Home