Dynamic forms with ASP.NET MVC and XML

June 28, 2009

A number of times in the past I’ve had the inclination to have a web form generated dynamically based on a templating system. Far too many times I’ve had to deal with changing requirements on large forms with tons of input elements, and it’s such a headache to modify them, particularly with ASP.NET Webforms. 

The problem with Webforms

While ASP.NET always had the capability of dynamic forms, it almost always turns out to be such a pain in the ass it’s not even remotely worth the hassle.  Use of dynamic ASP.NET web Controls is frustration defined.

With ASP.NET MVC (as well as new C# language features Linq to XML) we finally have the technology in place for implementing dynamic forms with ease.

XML to HTML

The idea here is to define all of your form fields (text box, radio buttons, drop down lists, etc) in an XML document while the .aspx View page dynamically renders it into Html.  If any change is required to the form fields (changing an attribute, or even adding/removing a field entirely – more on that later) it can be done to the definition in the XML document. No need to touch the View page, and certainly no need to touch code.

Below is my form elements represented by XML. This structure and naming convention was entirely… uh, pulled out of my ass for this demonstration. Certainly this is not complete enough for any real world usage. (Notes below)

image

What I’ve done is defined a root “form” element with a number of “sections,” where each section will represent an HTML <fieldset>.  Each field within has attributes for type, name and css class. I’ll even be supporting default values – as you can see I’ve inputted a value for the Biography field.

In this example I’m only dealing with input of type text, an obvious cop out since this will be the most simple and straightforward example. There’s nothing preventing you from representing any of the other HTML input elements here though!

Building the form

The controller action is really simple. All we need to do is pass the View the XML structure so it can build the form. Down and dirty, I’m just stashing an XElement containing the XML into ViewData. We’ll take care of everything else in the View page.

Controller action (GET)

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
    //load xml
    XElement xml = XElement.Load(Server.MapPath("~/App_Data/form1.xml"));
    ViewData["xml"] = xml;
    return View();
}

Let’s pause for a word of warning: the following view page is not exactly the prettiest, but it will get the job done for now. See if you can interpret what’s going on, then read the notes that follow.

<% XElement xml = (XElement)ViewData["xml"]; %>
<h2>XML-based Dynamic Form</h2>
<%Html.BeginForm(); %>

<%var q = from s in xml.Descendants("section")
          select s; %>

<%foreach(XElement sec in q) { %>
    <fieldset>
        <legend>Section <%=sec.Attribute("number").Value %></legend>
        <table>
            <%var qq = from f in sec.Descendants("field")
                       select f; %>
            <%foreach(XElement field in qq) { %>
                <tr>
                    <td><%=field.Attribute("name").Value %></td>
                    <td>
                        <%=Html.TextBox(field.Attribute("name").Value, field.Value, new { @class = field.Attribute("class").Value })%>
                    </td>
                </tr>
            <%} %>
        </table>
    </fieldset>
<%} %>

<input type="submit" value="Submit!" />

<%Html.EndForm(); %>

What’s happening here is fairly simple. We have an outer-loop that is iterating over the “section” elements in our XML (there are two of them, numbered 1 and 2) and create a fieldset that will contain a table to house our form fields. The inner loop is iterating over all of the field elements within the current section.  I’m using the value of the name attribute as the description for the field, and I’m creating an HTML textbox with a name of the name attribute, a value of the field element’s value (if present), and a class attribute from the attribute of the same name.

The rendered form

image

Review the XML above and see how it came out on the rendered form.  Note that the Biography input has the pre-set value as determined in the XML.  Why is it a different size? It’s been assigned a css class that has set the height and width as shown.

When the Submit button is clicked the name/value pairs of each of these form elements will be posted to the appropriate controller action, where the rest of the magic will happen.

To be continued?

As cool as this may be, we’ve only implemented half of the solution. What use is a dynamic form if the controller that it posts to is stupid?  We could bind this form to an arbitrary object or pick out form collection values, but what are we even looking for? We can’t hard-code the name values to retrieve or the application will blow up as soon as a form element or name changes!

Perhaps in a future segment we’ll address this issue…

Tags: dynamic forms, xml, mvc
Categories: ASP.NET MVC, C#, HTML

Upgrade to BlogEngine.NET 1.5

June 28, 2009

I just upgraded to BE.NET 1.5 and everything was a snap.  Keep your App_Data folder, update everything else, and done! Okay – depending on your setup you’ll also need to make sure you include all of your extensions and themes as well.

Improved Metaweblog API

As mentioned in this post, BE.NET 1.5 has an improved Metaweblog API.  I’m happy to report that creating and managing this post through Windows Live Writer has been much less a hassle than before. Setting a posting date (other than today) works!

BlogEngine.NET 1.5 release candidate can be found here.

Running and debugging NUnit tests through Visual Studio

June 18, 2009

Getting into this whole unit testing thing? Even for a newbie, following some of the new ASP.NET MVC and tutorials built on the "Test Driven Development” philosophy has been pretty easy. It only took a few steps and I was creating and testing actual tests with NUnit.

Wait. Testing the tests?

No one even mentioned that. And boy was I making some foolish mistakes and causing exceptions the first few times around while writing my tests.  But the NUnit GUI or console is a separate app that runs your test DLLs. How the heck can you debug?

It’s actually one quick & easy step in Visual Studio. Probably obvious and known to many, but I sure was perplexed at first.  Here’s what you need to do:

  1. Right-click on your tests project and open up the Properties window
  2. In the Debug section, under Start Action, select “Start externam program” and specify the path to your nunit.exe (save & close)
    image
  3. Right-click on your tests project and select “Set as StartUp project” if it isn’t already.
  4. Hit F5 and run!

Running will launch a new instance of the NUnit GUI and when you run the tests, any breakpoints will be hit and you can walk through your actual test methods in Visual Studio!

About me

I'm a consultant with Headspring in Austin, TX. My passion is creating web-based applications that are well crafted and solve real problems for real people. Want to know more? Check out my about page.

WTF is all this code? I came here for food!

My wife made a new year's resolution to try out at least one new recipe each week. Want to know what she's been feeding me? resolutionfood.blogspot.com