XSD -> Classes Generator Custom Tool (radically new and extensible)
Note: this entry has moved.
This article is a companion to
Code Generation in the .NET Framework Using XML Schema article
published in the MSDN XML DevCenter.
In that article, I introduce you to the main classes in the .NET framework that
enable code generation from XSD files, the very clases the XSD.EXE tool uses.
The ideas come from my initial post on Customizing
XSD->Classes code generation, the "easy" way.
In this article I'll show how the VS.NET custom tool included in the MSDN article code download is created.
Building the XsdCodeGen Custom Tool
Creating a custom tool for VS.NET is extremely easy. Microsoft has released a
project with all the necessary classes for that purpose, which can be
downloaded from GotDotNet
(http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=4AA14341-24D5-45AB-AB18-B72351D0371C).
Everything we need to do is create a new class library project using that one
as a skeleton, and add a new class inheriting from the BaseCodeGeneratorWithSite
provided:
The generator is registered as a COM component, and that’s why we need to specify the GuidAttribute and the ComVisibleAttribute. The former should receive a new GUID which can be created from the Tools -> Create GUID menu. We call it a generator because that’s the registry key they are registered under. That key has two sub keys, one for the VB.NET and another for the C# generators. We should register our tool with both, as we’re using the language-agnostic CodeDom. Therefore, we define two constants that hold the GUIDs of such categories:
We’ll also store the GUID assigned to the class itself for easy access, as we’ll need it for registration. We also define the custom tool name and description with constants. The former is important as it’s the one that is assigned to a file through the Property Browser in order to execute the tool:
The registry key we need to create looks like the following:
As we don’t have any dependencies on any VS version, we should register under both keys, “7.0” and “7.1”, replacing the {Version} part. Also, we will register for both language categories. We will store as a constant the full registry key skeleton to format with the variable parameters. The registration methods are:
Finally, we have to call these methods at COM registration/unregistration
time. We can specify the methods to be executed at that time, through the ComRegisterFunctionAttribute
/ComUnregisterFunctionAttribute
attributes:
After compiling the project, we need to run the following command (in a VS.NET command prompt) on the project output folder to register the custom tool:
And to unregister it:
Alternatively, you can go to the project properties dialog, under
Configuration Properties > Build, and set Register for COM Interop to true.
To run the custom tool for a file, we just need to set its Custom Tool
property to XsdCodeGen
.
Now we can finally move to the actual code generation inside the tool.
Generating Code
The first step is to factor out the code we used for the console application.
We will associate the custom tool with XSD files, so we will already have the
source filename in place. We won’t need the language because the BaseCodeGeneratorWithSite
base class we used already provides access to a CodeDomProvider
that
is the appropriate one according to the current project type where the file
lives in. Finally, as we specified at tool registration time that we would
generate source at design-time (GeneratesDesignTimeSource
registry
value), VS.NET will automatically generate a new file dependent on the schema
file, much like it does with a TypedDataset
schema and its
corresponding class file, a WebForm and its code-behind, a WinForm and its
resource file, etc. All we need is implement the following method from the tool
base class:
In order to better reuse code from the custom tool and the console app, we
will separate the XSD processing in a new class and we will make the console
app use this one by referencing the custom tool project. We could also create
an entirely new class library just for this purpose, too.
So, the GenerateCode()
method implementation is:
The new Processor
class has almost the same code as the console
app, but only generates the CodeNamespace
, leaving the
responsibility of generating the final source form to the caller. Note that the
base class for the tool already provides access to the appropriate ICodeGenerator
instance we mentioned, through the GetCodeWriter()
method. We can
also access the Custom Tool Namespace
property that appears in the
Property Browser
for a file, through the FileNameSpace
property.
We’re done with the tool now. We can start using it right away by associating
the XsdCodeGen
custom tool with any WXS file. Note that VS.NET
locks the assembly when the tool is run for the first time. Should we want to
keep modifying it and re-compiling, we will have to restart the IDE.
Extensions for codegen can be easily created to leverage the tool, simply by placing the extension assembly next to the custom tool installation folder, and adding the extension to the schema as follows:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
...etc...> <xs:annotation>
<xs:appinfo> <Code xmlns= "http://weblogs.asp.net/cazzu">
<Extension Type="XsdGenerator.Extensions.ArraysToCollectionsExtension, XsdGenerator.Library" />
<Extension Type="XsdGenerator.Extensions.FieldsToPropertiesExtension, XsdGenerator.Library" />
<Extension Type="MyExtensions.DoSomethingCool, MyExtension" />
</Code>
</xs:appinfo>
</xs:annotation>
You'll need those extensions in order to modify the default output that matches the xsd.exe one. Enjoy!