sgen.exe & multiple types

If you have ever used sgen.exe to generate/precompile serialization-assemblies, I’m sure you are surprised by the fact that it doesn’t allow you to specify multiple types to generate the classes for. After trying to find an alternative (and failed to do so), I decided to see if it’s possible to disassemble and alter sgen’s sourcecode. It is surprisingly simple. In this post, I’ll guide you through the steps I have taken.

First, download and install Reflector. Then locate sgen.exe. On my laptop, with VS2010 installed, it’s located at C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin. Open sgen.exe in Reflector, right-click sgen and choose ‘Export’. This will disassemble the executable and export all it’s content including a .csproj file; very convenient.

We now need to alter sgen’s source at a couple locations.

1. there is a fixed, absolute path to the key file originally used to sign the assembly. From the AssemblyInfo.cs remove:

[assembly: System.Reflection.AssemblyKeyFile(@"f:\dd\Tools\devdiv\FinalPublicKey.snk")]
[assembly: System.Reflection.AssemblyDelaySign(true)]

If desired, sign the assembly with your own key file.

2. in the file CommonResStrings.cs the class Assembly is used, but the corresponding using statement is missing. Add the using statement:

using System.Reflection;

3. next up is SgenTool\Sgen.cs. In the method ‘Run’ change:

~ line #356
string typeName = null;

to:

List<string> typeNames = new List<string>();
~ line #457
else if (this.ArgumentMatch(arg, "type"))
{
    typeName = str6;
}

to

else if (this.ArgumentMatch(arg, "type"))
{
    typeNames.Add(str6);
}
~ line #484
this.GenerateAssembly(typeName, assemblyName, list, proxyOnly, silent, warnings, debug, keepFiles, force, codePath, compilerOptions, parsableerrors);

to

this.GenerateAssembly(typeNames, assemblyName, list, proxyOnly, silent, warnings, debug, keepFiles, force, codePath, compilerOptions, parsableerrors);

Then change the signature of the GenerateAssembly method into:

~ line #109
private void GenerateAssembly(List<string> typeNames, string assemblyName, ArrayList references, bool proxyOnly, bool silent, bool warnings, bool debug, bool keepFiles, bool force, string codePath, string compilerOptions, bool parsableerrors)
~ line #124
if (typeName == null)
{
    types = assembly.GetTypes();
}
else
{
    Type type = assembly.GetType(typeName);
    if (type == null)
    {
        Console.Error.WriteLine(FormatMessage(parsableerrors, false, Res.GetString("ErrorDetails", new object[] { Res.GetString("ErrLoadType", new object[] { typeName, assemblyName }) })));
    }
    types = new Type[] { type };
}

to

if (typeNames.Count == 0)
{
    types = assembly.GetTypes();
}
else
{
    List<Type> typeList = new List<Type>();
    foreach (string typeName in typeNames)
    {
        Type type = assembly.GetType(typeName);
        if (type == null)
        {
            Console.Error.WriteLine(FormatMessage(parsableerrors, false, Res.GetString("ErrorDetails", new object[] { Res.GetString("ErrLoadType", new object[] { typeName, assemblyName }) })));
        }
        else
        {
            typeList.Add(type);
        }
    }
    types = typeList.ToArray();
}

And finally

~ line #216
else if (typeName == null)
{
    if (warnings)

to

else if (typeNames.Count == 0)
{
    if (warnings)

That’s it! Compile and enjoy your new multi-type-capable sgen.exe! You simply need to provide multiple /t command-line arguments.

note: I’ve written this post out-of-the-office and it’s a little untested. But I’m pretty sure, these are the steps I’ve did. If something’s not working for you, let me know and I’ll see what I can do. Also I’m not very thrilled about the current code-formatting in this post; I might fix that someday

6 thoughts on “sgen.exe & multiple types

  1. Hi,

    Is there any way to create an MSbuild task in VS 2008 using this? I’m mostly after the Types property.

  2. Hi, I’m sure that’s possible. But I’ve not been doing a lot of .NET lately, let alone building MSBuild tasks!

    But you can probably also use the ‘Exec’ task, or include it in a post-build event of a project?

  3. I thought so, but I would like to somehow integrate this as a new SGen task. The thing is, it does not support the Types attribute in VS 2008. Some other attributes would be great to keep as well for convenience, like References.

    I suppose I’ll just add another argument to SGen.exe called “/references”

  4. Thank you for the great description. It was exactly what I needed and worked like a charm!

    Great work!

  5. You can take this one step further and load the command line arguments from a file using this syntax: “sgen @commandline”. To do this change the following line in Main() from:

    return sgen.Run(args);

    to:

    return sgen.Run(LoadArgs(args));

    Then add the following static function:

    private static string[] LoadArgs(string[] args) {
    if (args.Length == 1 && args[0].StartsWith(“@”)) {
    string path = args[0].Substring(1).Trim();
    if (!File.Exists(path)) throw new FileNotFoundException(path);
    string[] lines = File.ReadAllLines(path);
    List trueLines = new List();
    foreach (var line in lines)
    if (!string.IsNullOrWhiteSpace(line)) trueLines.Add(line);
    return trueLines.ToArray();
    }
    return args;
    }

    Now, just add your sgen arguments to a text file and invoke the utility. This works well when you have a lot of types you want to include in the generated xml serializer assembly.

Leave a Reply

Your email address will not be published. Required fields are marked *