Generating ASP.NET MVC View Controls According to Xml Configurations
Last week I was consulting about ASP.NET MVC at a customer. One of the customer project requirements is to generate forms according to Xml configuration files. In this post I’ll offer an end-to-end solution to this requirement. This solution can be rafactored to use databases or any other data sources in order to achieve the same results.
Setting The Environment
Create a new default internet ASP.NET MVC 3 web application:
Pay attention to the folders I added such as Classes and ViewModels. The Classes folder will be used to store classes that I use in the application. The ViewModels folder will be used to store the view models that I’ll use in the solution.
The Xml File
Here is an example for the Xml file I’m going to use in the solution:
The Xml will be located in the App_Data directory. In the Xml, a view node represents a single view that holds some controls to render. Every control has a type (for example Label) and each type has properties that define the type. As you can understand this data structure can also be implemented inside a database or other storage types. Since the customer needed Xml representation I use an Xml file.
First Step – Creating the ViewModels for the Controls
The first thing to do is to create a base class to represent a control inside a view.
The ControlViewModel include the control type, the control id, the control name and a label string associated with the control. If you need other properties which are repeated in all your controls you can add them.
After we have the base class lets implement some concrete classes such as TextBox and Label:
In the concrete classes, I implemented the control type and added more properties that are used in that control.
Now that we have the concrete classes we can add a ViewModel that will hold all the list of controls for a view:
The DefaultControlsViewModel includes a list of all the controls to render. If you like to add more model properties to the ViewModel you can inherit from this class and add them.
Second Step – Creating the ControlsContext to Read the Xml File
After we have the ViewModels, we will create a class to read the Xml file (or read from your data source if you have chosen another data source). I have created a ControlsContext class to read the Xml file and to store a DefaultControlsViewModel for each view in the Xml. Here is the ControlsContext implementation:
Some things to notice:
- You can create this class as singleton since we will want only one instance for it.
- I use the HttpContext.Current.Server.MapPath("~/App_Data/Controls.xml") statement to get the path for the App_Data folder.
- I use LINQ to Xml to read the Xml file content.
- In order to create and fill the control view models I use the Activator.CreateInstance("DynamicControlsCreation", "DynamicControlsCreation.ViewModels." + type.FirstAttribute.Value + "ViewModel")
Third Step – Implement the HomeController Functionality
Now that we have the ControlsContext and the control ViewModel classes we can implement the controller functionality.
As you can see, I use the default generated ASP.NET MVC HomeController and implement the Index method and an Index method to handle HTTP posts. The reason for the second method will be explained in the last step.
Forth Step – Creating the Views and the Template Views for Each Control
We set all the environment but now we want to create our dynamic generated views. Here is the Index view:
As you can see, I iterate on all the controls in the DefaultControlsViewModel and write the relevant controls in the view. I use the HTML.EditorFor method to render the relevant view for the relevant control.
In the Views –> Shared folder, I added an EditorTemplates folder and put the relevant view templates for the controls view model (which will be used we you call the HTML.EditorFor method):
The last view that I added is the Submitted view:
The Views folder will look like:
Last Step – Create the ControlsModelBinder
If you’ll try to run the application everything will work except for the post to the Index method which is created when you click the submit button. The reason it won’t work is that ASP.NET MVC doesn’t know how to create the instances for the concrete control classes. This error can be solved by using a a model binder. If you aren’t familiar with ASP.NET MVC model binders you can read the following post. Here is the model binder to instantiate the relevant ControlViewModel class:
You will have to register that binder in the Global.asax file in the Application_Start event:
This is it.
Now you can run the application and see it working including the submit button in the homepage.
You can download the full code example from here.
In the post, I’ve created an end-to-end solution to handle dynamic controls creation in a view according to an Xml configuration file.