如何在ASP.NET MVC 2中验证和发布动态表单中的数据

时间:2011-05-09 15:33:05

标签: asp.net-mvc-2 asp.net-mvc-2-validation

我有一个已经被要求扩展的现有ASP.NET MVC 2应用程序。我正在为网站添加一个新功能,我根据从HR系统中检索到的动态问题列表生成员工评估表。除了验证和将响应发布回网站之外,我已经完成了所有工作。以下是一些细节:

  1. 我通过网络服务电话从我们的后端系统中检索“问题”列表。
  2. 每个“问题”包含要显示的文本以及以下设置:
    • 问题类型(对应于文本框,文本区域,单选按钮列表或复选框列表)
    • 如果允许评论
    • 如果需要答案
    • 适用时,可能的回复列表
  3. 要生成表单,我在问题列表中使用for-each循环。我使用QuestionType属性的值来确定要呈现的部分视图(每个类型一个)。例如,如果QuestionType == SingleChoice,则该部分将选项呈现为单选按钮列表。如果允许对问题发表评论,我还会渲染一个额外的textarea字段来保存用户的评论。

    正如我所说,渲染表单工作正常,但现在我需要:

    一个。在需要答案时强制执行。我在解决方案的其他地方使用DataAnnotations进行验证,但由于我不是在反对静态模型,我不知道如何做到这一点。

    B中。将结果发布回网站。对于每个问题,可以在文本框或文本区域中输入文本,为单选按钮列表选择一个值,或为复选框列表输入多个选定值。另外,每个问题还可以以评论的形式发回其他文本。

    我看到的所有使用动态“列表”的示例仅涉及为每个字段发布单个值,并且它始终是相同的类型(例如文本框列表)。由于我必须支持的变化,再加上需要发回输入/选定的值和每个问题的评论,我很难过。

    感谢任何指导。

1 个答案:

答案 0 :(得分:1)

我刚刚完成了完全相同的任务。

我选择为动态表单对象编写自定义模型绑定器。模型绑定器为隐藏字段提取了一堆带有前缀的表单键,其中包含一些有关该问题的分隔元数据(即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());

因此,收到表单帖子的操作方法类似于:

public ActionResult ProcessForm(DynamicForm form) {
    if(ModelState.IsValid) 
    {
        DynamicFormService.Process(form);

        return RedirectToAction("TheHttpGetAction");
    }
    return TheHttpGetAction();
}