ASP.NET MVC中使用动态表单的建议

时间:2009-06-24 19:38:46

标签: .net asp.net asp.net-mvc http dynamic-forms

我正致力于在ASP.NET MVC视图中渲染动态表单,以满足这些要求:

  • 可以验证字段
  • 表单无效时保留状态

我正在研究创建一个自定义模型绑定器来实现这一目标。我一般打算这样做:

  1. 使用这些属性定义表单字段
    • 提示(字段旁边的标签)
    • 类型(文字,复选框列表,放射学家等)
    • 选择(列表字段)
    • IsRequired
    • RegularExpression(用于文本字段)
    • 显示选项
    • 字段定义的集合从控制器发送到视图
    • 字段呈现为HTML并发送到浏览器
    • 表单将发送回服务器
    • 自定义模型绑定器 将表单绑定到现在包含提交值的字段定义集合
    • 每个字段都经过验证
    • 如果需要 - >必须有一个值
    • 如果RegEx - >必须匹配
    • 对于每个无效字段,都会向modelstate
    • 添加一条错误消息
    • 控制器决定做什么
    • 如果所有字段都有效
      • 对字段及其值进行任何操作
    • 如果1个或多个字段无效
      • 将字段集合发送回视图
      • 使用之前尝试的值
      • 再次渲染字段
      • 显示验证摘要
  2. 我不确定我是以最好还是最简单的方式做这件事。这种方法会给我带来很多问题甚至工作吗?我该怎么做才能改进它?

4 个答案:

答案 0 :(得分:8)

我写了一个类库,它基本上完全符合我的问题中描述的psuedocode。它很棒。

编辑:

我终于清理了我的班级图书馆。我添加了一些新功能,并创建了一个记录良好的演示Web应用程序。

所有这些都是hosted here on CodePlex。我希望这有助于某人。

答案 1 :(得分:0)

我不是专家,但如果你是ASP.NET MVC的新手,那么我建议你在开始自己的内置功能之前先使用内置功能。它完成了你所描述的大部分内容,除了不鼓励在控制器中定义/构建UI,因为这是视图的工作。

通过ModelStateDictionary,您可以添加模型错误并设置模型值,然后在验证失败时将其绑定到表单输入。

更新:另一种看待它的方法:问问自己为什么使用MVC而不是经典的ASP.NET构建技术,然后看看你提出的方法是否符合这些原因。对我来说,分离关注点是一个很大的原因,以及对生成的HTML的精细控制,我觉得你的方法可能会颠覆这些事情。

专门解决您的编辑问题:

第1步到第1步是针对MVC范例的。 第4步,很好。 步骤5到7是非常标准的MVC实践,并且完全受框架支持。例如,Performing Simple Validation (C#)显示了验证和错误消息表示的示例。

答案 2 :(得分:0)

虽然不是专家,但我必须创建一个解决方案,其中我的主对象有一个值列表。让我们称之为对象A有一个映射在数据库中的ApplicationValues列表。 ApplicationValues有一个Key(表单字段,例如PhoneNumber)和Value。

由于ApplicationValues是一个EntitySet,我必须创建get和set方法来正确处理设置特定的ApplicationValue。我在我的数据库中还有一个ApplicationRules列表,它定义了这些应用程序值可以采用的内容。

以下是一段代码,可帮助您根据自己的需求开发解决方案。

public partial ApplicationValue
{
    public string Key;
    public string Value;
}

public partial ApplicationRule
{
    public string ValidationFormat;
    public string ValidationError;
    public bool Required;
}

public partial class A
{
    public void SetValue(string key, string value)
    {
        //ApplicationValues is the list of values associated to object A
        ApplicationValue v = ApplicationValues.SingleOrDefault
        (k => k.Key == key);

        //if we already have this value
        if (v != null)
        {   //...then we can simply set and return
            v.Value = value;
            return;
        }

        //else we need to create a new ApplicationValue
        v = new ApplicationValue
            {
                AffinityID = this.ID,
                Key = key,
                Value = value
            };

        ApplicationValues.Add(v);
    }

    public string GetValue(ApplicationField key)
    {
        return GetValue(key, String.Empty);
    }

    public string GetValue(ApplicationField key, string defaultValue)
    {
        if (ApplicationValues == null)
            return defaultValue;

        ApplicationValue value = ApplicationValues.SingleOrDefault
        (f => f.Key == key.ToString());

        return (value != null) ? value.Value : defaultValue;
    }

然后进行表单验证,我遍历ApplicationRules(定义是否需要字段,包含正则表达式等)并将其与FormCollection匹配。

public ActionResult Details(FormCollection form)
{
    IList<ApplicationRule> applicationRules = //get my rules from the DB

    if (!(ValidateApplication(applicationRules, form, a)))
    {
        ModelState.AddModelError("message", "Please review the errors below.");
        return View(a);
    }
    ...
}

private bool ValidateApplication(IList<ApplicationRule> applicationRules,
                                 FormCollection form, A a)
    {
        //loop through the application rules
        foreach (ApplicationRule ar in applicationRules)
        {
            //try and retrieve the specific form field value using the key
            string value = form[ar.Key];

            if (value == null)
                continue;

            //set the model value just in case there is an error
            //so we can show error messages on our form
            ModelState.SetModelValue(ar.Key, ValueProvider[ar.Key]);

            //if this rule is required
            if (ar.Required)
            {   //...then check if the field has a value
                if (String.IsNullOrEmpty(value))
                {
                    ModelState.AddModelError(ar.Key, "Field is required");
                    continue;
                }
            }

            //if this rule has a validation format
            if (!String.IsNullOrEmpty(ar.ValidationFormat))
            {   //...then check the value is of the correct format
                Regex re = new Regex(ar.ValidationFormat);

                if (!re.IsMatch(value))
                {
                    ModelState.AddModelError(ar.Key, ar.ValidationError);
                    continue;
                }
            }

            a.SetValue(ar.Key, value);
        }

        return ModelState.IsValid;
    }

答案 3 :(得分:0)

您的字段定义有多动态?如果它们不经常更改,则可以在创建定义后使用代码dom生成模型和控制器。我没有在ASP.NET MVC中尝试这个,但它可能是一个好方法。

http://msdn.microsoft.com/en-us/library/y2k85ax6.aspx

本文使用代码dom进行ActionLink生成。

http://blogs.msdn.com/davidebb/archive/2009/06/01/a-buildprovider-to-simplify-your-asp-net-mvc-action-links.aspx#comments