简体   繁体   中英

How to build flexible web forms in ASP.NET

I'm using asp.net and I need to build an application where we can easily create forms without recreating the database, and preferably without changing the create/read/update/delete queries. The goal is to allow customers to create their own forms with dropdowns, textboxes, checkboxes, even many-to-one relationship to another simple form (that's stretching it). The user does not have to be able to create the forms themselves, but I don't want to be adding tables, fields, queries, web page, etc. each time a new form is requested/modified.

2 questions: 1) How do I structure a flexible database to do this (in SQL Server)? I can think of two ways: a) Create a table for each datatype (int, varchar(x), smalldatetime, bit, etc). This would be very difficult to create the adequate queries. b) Create the form table with lots of extra fields and various datatypes in case the user needs 5 integers or 5 date fields. This seems the easiest, but is probably pretty inefficient use of space.

2) How do I build the forms? I thought about creating an xml sheet that had the validations, data type, control to display, etc. as a list. Then I would parse through the xml to build the form on the fly. Probably using css to do the layout (that would have to be manual, which is ok).

Is there a better/best way? Is there something out there that I could look at to get ideas? Any help is much appreciated.

This sounds like a potential candidate for an InfoPath solution. At first blush, it will do most/all of what you are asking.

This article gives a brief overview of creating an InfoPath form that is based on a SQL data source.

http://office.microsoft.com/en-us/infopath-help/design-a-form-template-based-on-a-microsoft-sql-server-database-HP010086639.aspx

I have built a completely custom solution like you are describing, and if I ever did it again I would probably opt for either 1) a third-party product or 2) less functionality. You can spend 90% of your time working on 10% of the feature set.

EDIT: reread your questions and here is additional feedback.

1 - Flexible data structure: A couple things to keep in mind are performance and the ability to write reports against the data. The more generic the data structure, the harder these will be to achieve (again, speaking from experience).

Somewhat contrary to both performance and report-readiness, Microsoft SharePoint uses XML fragments/documents in generic tables for maximum flexibility. I can't argue with the features of SharePoint, so this does get the job done and greatly simplifies the data structure. XML will perform well when done correctly, but most people will find it more difficult to write queries against XML. Even though XML is a "first class citizen" to SQL Server, it may or may not perform as well as an optimized table structure.

2 - Forms: I have implemented custom forms using XML transformed by XSLT. XML is often a good choice for storing form structure; XSLT is a monster unto itself, but it is very powerful. For what it's worth, InfoPath stores its form structure as XML.

I've also implemented dynamic forms using custom controls in .Net. This is a very object-oriented approach, but (depending on the complexity of the UI) can require a significant amount of code.

Lastly (again using SharePoint as an example), Microsoft implemented horrendously complicated XML list/form definitions in SharePoint 2007. The complexity defeats many of the benefits. In other words, if you go the XML route, make your structures clean and simple or you will have a maintenance nightmare on your hands.

EDIT #2: In reference to Scott's question below, here's a high-level data structure that will avoid duplicated data and doesn't rely on XML for the majority of the form definition.

Caveat: I just put this design together in SQL Management Studio...I only spent 10 minutes on it; developing a flexible form system is not a trivial task, so this is an over-simplification. It does not address the storage of user-entered data, just the definition of the form.

替代文字

The tables:

Form - top-level form table which contains (as you would guess) the collection of fields that comprise the form.

Field - generic fields that could be reused across forms. For example, you don't want 50 different "Last Name" fields for 50 different forms. Note the "DataTypeId" column. You could store any type you wanted in this column, like "number, "free text", even a value that indicates the user should pick from a list.

FormField - allows a form to contain 0-many fields in its definition. You could even extend this table to indicate that the user can ADD as many of this field as they need.

Constraint - basically a lookup table that defines a constraint type (maybe it's max length, max occurrences, required, etc.)

FormFieldConstraint - relates a constraint to a particular instance of a form field. This table combines a specific form with a specific field with a specific constraint. Note the metadata column; this potentially would be a good use for XML to store the specifics of the constraint.

Essentially, I suggest building a normalized database with few or no null values and no duplicated data. A structure as I've described would get you on the path to that goal.

I think if you need truly dynamic forms saved into a database, you'd have to create a sort of "dictionary" data table.

For example...

UserForms
---------
FormID
FieldName
FieldValue

FormID relates back to the parent form (so you can aggregate all of the fields for one form. FieldName is the name of the text field entered from. FieldValue is the value entered/selected for that field.

Obviously this isn't a perfect solution. You could have issues typing your data dynamically, but I leave the implementation of that up to you.

Anyways, hopefully this gives you somewhere to start thinking about how you'd like to accomplish things. Good luck!

PS I've found using webforms with .NET to be a total pain when doing dynamic form generation. In the instances I had to do it, I ditched it almost entirely and used native HTML elements. Then rewired my form by using the necessary values from Request . Probably not a perfect solution either, but it worked the best for me.

We created a forms system like the one you're describing with a schema very similar to the one at the end of Tim's post. It has been pretty complicated, and we really had to wrestle with the standard WebForms controls like the DetailsView and GridView to make them be able to perform CRUD operations on groups of answers. They're used to binding straight to properties on an object, and we're forcing them to look up a field ID in a dictionary first. They don't like it. You may want to consider using MVC.

One tricky question is how to store the answers. We ended up using a table that's keyed on FieldId, InstanceId (for example, if 10 people are filling out your form, there are 10 instances), and RowNumber (because we support multi-row forms for things like employment history). Instead of doing it this way, I would recommend making your AnswerRow a first-class concept with its own table tied to an Instance, and having the answers be linked to the AnswerRow and Field.

In order to support different value types, we had to create multiple answer fields on our answer table (AnswerChar, AnswerDate, AnswerInt, AnswerDecimal). Each of these maps to one or more Field Types (Date, Time, Number, etc.). Each Field Type has its own logic to represent the value in the UI, and put the value into the appropriate property on our answer objects.

All in all, it's been a lot of work. It's worth it for us, since this is the crux of the product, but you will definitely want to keep the cost in mind before embarking on a project like this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM