我刚刚完成了完全相同的任务。
我选择为我的动态表单对象编写一个自定义模型绑定器。模型绑定器为隐藏字段提取了一堆前缀表单键,其中包含一些关于问题的分隔元数据(即 IsRequired、QuestionType、QuestionId 等)
我正在使用 MVC3,但我认为这应该在 MVC2 中都可以工作。
我创建了一个 ModelBinder,如:
public class DynamicFormModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Create the object to be bound to (I had a kind of form object
// with a simple list of answer objects
DynamicForm form = new DynamicForm(new List<Answer>());
HttpRequestBase request = controllerContext.HttpContext.Request;
var keys = request.Form.AllKeys.Where(k => k.StartsWith("MyFormsKeyPrefix_Meta_"));
foreach (var key in keys)
{
// Loop over each question's meta data. Metadata will always be present
// even if the user hasn't selected an answer as it's a hidden field
// TODO: Split the meta data and pull out IsRequired, QuestionType etc
// TODO: Get all the posted form values for the question (these values
// will come from textboxes, dropdowns, checkboxes etc)
// Use a prefix like: MyFormsKeyPrefix_Answer_{QuestionId}
// textboxes & dropdowns will only ever have one value
// but checkboxes could have multiple
// TODO: If it's a mandatory question then ensure there is at least
// one posted value that is not an empty string
// If there is a validation error then add it to the model state
bindingContext.ModelState.AddModelError(key, "Field is required");
foreach(var answerHtmlName in answerHtmlNames)
{
// TODO: Loop over each posted answer and create some kind of nice
// Answer object which holds the QuestionId, AnswerId, AnswerOptionId
// and Value etc.
// Add the answer to the forms answers list
form.Answers.Add(answer);
}
}
return form;
}
}
我使用以下方法在 Global.asax 中注册了 ModelBinder:
ModelBinders.Binders.Add(typeof(DynamicForm), new DynamicFormModelBinder());
因此,接收表单 post 的操作方法如下所示:
public ActionResult ProcessForm(DynamicForm form) {
if(ModelState.IsValid)
{
DynamicFormService.Process(form);
return RedirectToAction("TheHttpGetAction");
}
return TheHttpGetAction();
}