David Kennedy’s Tech Ramblings

Just another WordPress.com weblog

POCO2HTML Form Generator September 11, 2008

Filed under: Uncategorized — dotnetdave @ 2:54 am

I sometimes wake up in the early hours of the morning with some idea running around in my head, and this morning it just happened to be this. I have had similar thoughts in the past, as would have most developers who become bored with the repetition of writing input HTML forms that directly match model classes for your data. Here is a working start to a command line utility that reflects on a given assembly and produces simple HTML forms to match.

When I have some more spare time after my 70-536 MS exam I’d like to tidy this up to make it more useable as well as generating c# code to populate an object from the form back on the server. As I’ve been experimenting with the new ASP.NET MVC this is generating a plain HTML form, however the output could easily be adapted to produce rich server controls for input.

Here’s the code so far:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using keithfletcher.org; // courtesy of http://sql.codeproject.com/KB/dialog/CmdLineParsing.aspx using System.IO; using System.Reflection; namespace DotNetDave.Tools.POCO2HTML { [Application( HelpOptions = new string[] { "?", "help" }, OptionPrefixes = new char[] { '/', '-' }, ThrowParsingExceptions = false)] [Option("ns", ShortDescription = "Namespace", LongDescription = "The Namespace which contains Model classes from which to generate HTML forms.", ValuePresence = OptionAttributeValuePresence.MustHaveValue, IsOptional = true)] [Option("class", ShortDescription = "Class", LongDescription = "The fully-qualified class from which to generate a HTML form.", ValuePresence = OptionAttributeValuePresence.MustHaveValue, IsOptional = true)] [Option("all", ShortDescription = "AllTypes", LongDescription = "Generates HTML forms for ALL types in the given Assembly", ValuePresence = OptionAttributeValuePresence.MustNotHaveValue, IsOptional = true)] [Option("SourceFile", IsAnonymous = true, ShortDescription = "FileName", LongDescription = "The Assembly containing the Model/s to generate HTML form/s for.", ValuePresence = OptionAttributeValuePresence.MustHaveValue, IsOptional = false)] public class Program : CommandLineBase { static void Main(string[] args) { new Program(args); } private Program(string[] args) : base(args) { if ((Options.Count == 0) && !ShowingHelp) ShowHelp(); if (ParseErrors && !ShowingHelp) { WriteLine("Errors occurred!"); ShowHelp(); } // verify that the assembly exists if (!ShowingHelp && !File.Exists(Options["SourceFile"].Value)) { WriteLine("Source file specified is invalid! Please check the path and try again"); ShowHelp(); } // continue unless there's a problem if (!ShowingHelp) { Assembly source = Assembly.LoadFrom(Options["SourceFile"].Value); // if a class is specified, use it if (Options["class"].HasValue) { Type t = source.GetType(Options["class"].Value, false, true); ClassHtmlGenerator.Process(t); } else if (Options["ns"].HasValue) WriteLine("Not Yet Implemented"); else { if (Options["all"].IsPresent) { Type[] Types = source.GetTypes(); // generate for all types foreach (Type t in Types) { ClassHtmlGenerator.Process(t); } } else // list all available types { WriteLine("Available Types in Assembly:"); Type[] Types = source.GetTypes(); // Display all the types contained in the specified assembly. foreach (Type t in Types) { Console.WriteLine(t.Name + " (" + t.FullName + ")"); } } } WriteLine("Processing Complete!"); } Console.ReadKey(); } } public class ClassHtmlGenerator { public static void Process(Type SourceClass) { PropertyInfo[] props = SourceClass.GetProperties(); if (props.Count() == 0) return; // ignore types with no properties // start a target file StreamWriter target = new StreamWriter(SourceClass.Name + "Form.html"); target.WriteLine("<form id=\"Form1\">"); target.WriteLine("<table width=\"90%\">"); foreach (PropertyInfo prop in props) { if (prop.CanWrite) { target.Write("<tr><td>" + prop.Name + "</td>"); if (prop.PropertyType == typeof(string)) target.WriteLine("<td><input type=\"text\" name=\"" + prop.Name + "\"></td></tr>"); else if (prop.PropertyType == typeof(bool)) target.WriteLine("<td><input type=\"checkbox\" name=\"" + prop.Name + "\"></td></tr>"); else if (prop.PropertyType == typeof(DateTime)) // include simple datetime picker target.WriteLine("<td><input type=\"text\" name=\"" + prop.Name + "\"></td></tr>"); else if (prop.PropertyType.IsEnum) // offer options { target.Write("<td><select name=\"" + prop.Name + "\">"); foreach (FieldInfo fInfo in prop.PropertyType.GetFields(BindingFlags.Public | BindingFlags.Static)) { target.Write("<option value=\"{0}\">{1}</option>", fInfo.GetRawConstantValue().ToString(), fInfo.Name); } target.WriteLine("</select></td></tr>"); } else if (prop.PropertyType.IsValueType) // default to text input for now target.WriteLine("<td><input type=\"text\" name=\"" + prop.Name + "\"></td></tr>"); } } target.WriteLine("</table></form>"); target.Flush(); target.Close(); } } }


You’ll need to include the CmdLineParsing project from:


An example of the input and output is as follows:

public class TestClass { public enum StatusEnum { good, bad, ugly }; public string Title { get; set; } public StatusEnum Status { get; set; } public bool Active { get; set; } }

And this will produce the following form:

<form id="Form1"> <table width="90%"> <tr><td>Title</td><td><input type="text" name="Title"></td></tr> <tr><td>Status</td><td><select name="Status"><option value="0">good</option><option value="1">bad</option><option value="2">ugly</option> </select></td></tr> <tr><td>Active</td><td><input type="checkbox" name="Active"></td></tr> </table></form>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s