Discover a set of controls that provides a very productive and flexible way of creating ASP.NET web forms.
The source code
The project described in this article is hosted on mform.codeplex.com.
You will find the most recent version (the project is recently updated) here.
Introduction
It is most likely that you have seen probably the best beer in the Worldcommercial. Less chances are that you have heard of the
MForm webcontrols. And if you are like me a web developer struggling with
writing web forms that collect and process loads of data, you surely might find
the described controls interesting.
Project background
The MForm webcontrols project has been started in the IT departament of Bank Millennium,
Poland, a place where I work. It has been recently published under the Microsoft
public license.
If you have ever applied for a loan or a mortgage, you already know that banks want to know as much as possible about their clients to minimize the risk of giving too much money to a person that cannot afford returning it in the
future. All of this data is filled in by bank consultants into bank's intranet application
during a meeting with the client.
The duty of a bank IT developer is then to:
define the data contract (a data structure and data restrictions) for the information
that the business department wants to collect;
create a web form (or several web forms) that collects the data according to the
data contract;
validate the fields in the web form against data restrictions;
combine the data from the fields into the data structure;
Finally the data is sent somewhere else, where it is used to make a decision about
the client.
What struck me, was that all of these tasks looked like they could be made at least
partially automatically. The forms could be generated directly from the data contract
(in our case the data contract was defined using XML schema), the validations (at
least those basic ones as checking field requirement, its maximal length, matching
a pattern or maximal value) could be also taken from the data contract, finally
the data combining (creating an output XML instead of a collection of fields) could
be done automatically.
Still, the solution had to be extensible enough to:
allow modifying the created forms visually after the generation;
allow adding custom business validations that would work the same way data validations
work;
make the process of creating the forms as easy as possible, so that even an unexperienced
developer could prepare at least a web form sketch;
be efficient and use Ajax to eliminate unnecessary PostBacks;
use generic ASP.NET controls and solutions wherever possible;
Generating your first MForm web form
1.
Get the contract.
To be able to generate a form, you first need to have data definitions. It is best
if you have these definitions in XML schema (as XML schema provides a way to declaratively
define data restrictions not currently available in code), but if you are not familiar
with XML schema, you can also generate a form from a managed library.
In the following example we will use a Customer data definition:
[generation_1.png]
The Customer has:
a first and last names, which cannot be longer than 20 characters,
national id,
a birth date (of type date),
sex, which can be only of value 'Male' or 'Female'
and the address, which consists of:
street of maximal length 100,
house number of maximal length 10,
flat number, which is optional,
post code, which has to match the pattern two digits - three digits,
city of maximal length 50
Assuming that you have already downloaded the project code, you will find the Customer
data definition in the BM.Tools.WebControls.MForm.Example/Schemas/Customer.xsd
file.
2. Create a page with the MForm Root control
Open the project in Visual Studio 2008.
Create a new item -> Web Content Form in the BM.Tools.WebControls.MForm.Example
project
Drop the Root control on the page. It should look like this:
[generation_3.png]
Change the designer mode to Edit
3. Click the load a root template from schema button
You will see the generator form:
[generation_4.png]
4. Choose the contract source and location
Click the choose button and select the XML schema, wsdl or assembly
file. Then click Open
The Element name dropdown list will be propagated with available
elements (One XML schema file may have more than one element definition, same as
one assembly may have more than one class)
[generation_5.png]
5. Select the element
Once you select one of the elements from the dropdown list, the element tree will
be displayed. You have a possibility to decide which definitions should be rendered
in the form. By default the whole tree is prepared to be rendered. To change this,
uncheck the checkboxes near the elements:
[generation_6.png]
6. Click Generate
Once you click Generate, the Root control is filled in with the
content. The Root designer mode is changed to View mode so you
can see the result:
(The rendering in the designer mode is not perfect, the actual page display may
vary ):
[generation_7.png]
7. Switch to Source View
The generated form is available in the source view and can be freely modified. We
will take a closer look at the generated code:
The generated code in aspx may look a little scary at first. There is quite a lot
of data that has been generated. Of course you are not needed to understand all
of the generated code unless you want to change it somehow.
The Root control has three elements inside:
UriMappings element
Contents element
Validator element
The UriMappings
The UriMappings element keeps data about prefix and namespace mappings in the data
definition. In the case of our example, no namespaces were used, so there is only
one mapping, an empty prefix is mapped to an empty namespace.
The Validator
The Validator element is responsible of displaying the form validation errors. It
plugs the MForm tree in the ASP.NET page validation mechanism.
The Contents property
Finally, the Contents element is the most important part of the
Root control. The Contents property is a template that is instantiated
on page rendering, so it may contain any valid aspx script code: html code, web
controls, etc.. By default it only contains the generated controls. You can see
a Branch control with a property name equal Customer.
This control also has the Contents property, which again may contain
any aspx script code.
Branches and leafs
The Branch controls are those that represent data definitions that
had children. The data definitions that collected text are represented by the Leaf
controls. The Leaf controls do not contain the Contents property.
Instead, they may contain the ValueHandler element, which provides a communication
between the MForm tree and a control that should actually collect the data.
Value handlers
By default all data is collected using TextBoxes, so the default value handler is
the TextBoxValueHandler. The MForm framework provides value handlers for the generic
.NET form webcontrols. If you want to use your own custom control with the MForm
framework, you have to implement a value handler for this control.
The example of a different value handler is in a Leaf called
Sex. The data definitions allowed only two values in this element:
Male or Female. This has been ported to the form as a listbox control, that has
to corresponding list items. If you prefer using i.e. the RadioButtonList instead
of the ListBox, you can change the value handler to a RadioButtonListValuehandler,
and its inner control to RadioButtonList.
Data type
Do you remember that our customer data definition had a BirthDate
field, which was of type date. You can now see that the BirthDate
leaf has a property DataType of value Date. This
asserts that this field data must be provided in a valid date format.
Additions
Another definition that may be found inside the Leaf control is the Additions.
Additions may contain a list of controls that inherit from the
Addition control. The Addition control adds some
logic to the MForm control, it can for example add a data constraint. The Addition
controls that can be found directly after generation are data restrictions taken
from XML schema. So if in our data contract the PostCode field had to match the
pattern: 2 digits - 3 digits, we will a Restriction addition of
restriction type Pattern and value \d{2}-\d{3}
in a leaf called PostCode.
The Ordinal property
One last thing that is worth explaining is the Ordinal property.
The MForm webcontrols were designed to maximally facilitate the creation of web
forms, but still to give the possibility of editing this form after generation.
One can freely modify a once generated form, only remembering that the generated
MForm children cannot be moved outside their parents.
So inside the Contents property it is allowed to:
add some html code or controls;
place MForm child control inside these added controls (e.g. all Leaf controls can
be placed inside a table);
extract a part of a generated code and place it in an external user control, and
add a reference to this control inside the Contents;
change the order of MForm siblings;
When creating an output xml from the tree of MForm controls, two factors are taken
into account:
the hierarchy of the XML nodes - if MForm children are not moved outside their parents,
the MForm hierarchy remains intact, so the hierarchy of XML nodes will also be valid;
the order of XML nodes - because the order of controls can be changed, the
Ordinal property is generated. When the output xml is rendered, the MForm
controls are sorted by the Ordinal property value, which asserts, that the order
of XML nodes is valid
If you do not care about the order of XML nodes (i.e. deserializing xml to objects
using the .NET XmlSerializer class in most of the cases totally ignores the order
of XML nodes), you can turn off generation of the Ordinal property in the generator
under the options tab.
8. Run the page
Add an asp button to the page.
Then set it as the start page and run the project.
You will see that the form works and is validated. You can also see that the data
is persisted during postbacks.
If you get the OutputXml property of the Root control after the
form was filled in, you will get an Xml document that conforms to the Xml schema
from which we have generated the form. This is much more convenient than taking
care of each of the fields separately.
What's next?
I will try to post some more articles concerning the MForm webcontrols. The project
is still in alpha stage but we are very close to our first stable release. Until
that time, you are welcome to familiarize yourself with the MForm webcontrols using
the BM.Tools.WebControls.MForm.Example project. We will be most
grateful for submitting bugs and comments at mform.codeplex.com. You can also
see the example project at
mform.org.