Developers periodically find themselves with the need to have utilities to generate large amounts of templated C# code (a common example would be class files from either a database or text file). There are a number of options for writing code generation utilities, from CodeSmith to manually building up large strings in your C# code; some obviously easier and faster for the developers to write than others. For developer’s who, for reason’s involving ease of use or familiarity, would like to use an environment similar to asp.net for managing their templates, I would point out they do have the option of actually using asp.net. Nothing about asp.net actually requires the textual output for an .aspx page to be html.
Read on to see a basic implementation of the idea.
Here’s a quick example project to demonstrate the concept and does some encapsulation of the reusable code into shared and base classes.
The general strategy implemented is:
- Have one .aspx page per template
- Your code generation utility or client sends a HttpWebRequest to that page to generate the text from a template
- Serialize your arguments for the template to XML
- Post the text of the XML-serialized arguments as part of your HttpWebRequest, like you would an attached file to an html page
- Read the Response’s stream to get your generated file
Just from experience, you’ll might also want to include meta-data with the reponse, such as, this text is being generated for a file, what should that file be called (e.g. I’m generating a C# class file, the file should be named after the class), and what type of file is it (e.g. you might be writing a utility that wants to keep a list of generated sql files that get generated to give the user the option to enumerate through and execute them).
To implement responses as classes that can have meta data (such as file names) about the generated text coming back, I expanded the “Read the Response” step above into the following.
- Have a common, XML-serializable, response class that has a CDATA Section for holding the generated text and has properties for whatever other meta-data you want with your file.
- Override OnRender for your template .aspx page. Render out the page to a temporary string.
- Create an instance of the repsonse class, set its properties accordingly, serialize it to xml, and write it out to the Render method’s XmlTextWriter.
- Have the client utility read the Response’s stream and deserialize the text as your response object
A lot of this logic can be wrapped up in base and re-usable classes. Here is an example project that uses showing how one might implement those re-usable classes and an example of how to call them. In this case, to keep the example of how to use the classes and setup simple, the example calls to the template pages is also in the web project. In practice you might want to write a windows application and a web application, in which the web application is for the templates and the windows application contains the UI for your code generation utility.
The names of the relevant classes in the code example are:
- CodeGenerationPage (base class for your template pages)
- CodeGenerationRequest (class to encapsulate class to CodeGenerationPages)
- CodeGenerationResponse (class containing the generated text and the meta-data about it)
- CodeGenerationResponseWriter (a class for taking the responses and writing them out to the hard drive).
It should be noted that removing the Form runat=”server” tag in the template/aspx page takes away intellisense for your controls in visual studio (the work around to this woulbe leaving in the boilerplate html while writing/updating the html, but then deleting the html before checking-in/committing/using your changes). Another option would be a variant on what was presented here and move the templates to user controls and have the page containing the user control override its RenderControl method and have it only render out its template user control or possibly an xml-serialized object that represents a collection of mutiple template response objects.
So you can see, there’s a little bit of groundwork one has to do to use asp.net for their code generation, but once it’s done and it only has to be done once.