我有一个已经被要求扩展的现有ASP.NET MVC 2应用程序。我正在为网站添加一个新功能,我根据从HR系统中检索到的动态问题列表生成员工评估表。除了验证和将响应发布回网站之外,我已经完成了所有工作。以下是一些细节:
要生成表单,我在问题列表中使用for-each循环。我使用QuestionType属性的值来确定要呈现的部分视图(每个类型一个)。例如,如果QuestionType == SingleChoice,则该部分将选项呈现为单选按钮列表。如果允许对问题发表评论,我还会渲染一个额外的textarea字段来保存用户的评论。
正如我所说,渲染表单工作正常,但现在我需要:
一个。在需要答案时强制执行。我在解决方案的其他地方使用DataAnnotations进行验证,但由于我不是在反对静态模型,我不知道如何做到这一点。
B中。将结果发布回网站。对于每个问题,可以在文本框或文本区域中输入文本,为单选按钮列表选择一个值,或为复选框列表输入多个选定值。另外,每个问题还可以以评论的形式发回其他文本。
我看到的所有使用动态“列表”的示例仅涉及为每个字段发布单个值,并且它始终是相同的类型(例如文本框列表)。由于我必须支持的变化,再加上需要发回输入/选定的值和每个问题的评论,我很难过。
感谢任何指导。
答案 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();
}