9

我正在努力在满足这些要求的 ASP.NET MVC 视图中呈现动态表单:

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

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

  1. 表单字段是使用这些属性定义的
    • 提示(字段旁边的标签)
    • 类型(文本、复选框列表、单选列表等)
    • 选项(用于列表字段)
    • 是必须的
    • 正则表达式(用于文本字段)
    • 显示选项
    • 字段定义的集合从控制器发送到视图
    • 字段被渲染成 HTML 并发送到浏览器
    • 表单被发送回服务器
    • 定义模型绑定器将表单绑定到现在包含提交值的字段定义集合
    • 每个字段都经过验证
    • 如果需要 -> 必须有一个值
    • 如果 RegEx -> 必须匹配
    • 对于每个无效字段,都会在 modelstate 中添加一条错误消息
    • 控制器决定做什么
    • 如果所有字段都有效
      • 对字段及其值做任何事情
    • 如果 1 个或多个字段无效
      • 将字段集合发送回视图
      • 使用之前尝试的值再次渲染字段
      • 显示验证摘要

我不确定我是否以最好或最简单的方式这样做。这种方法会给我带来很多问题甚至是工作吗?我能做些什么来改进它?

4

4 回答 4

8

我写了一个类库,它基本上完全按照我的问题中的伪代码描述的那样做。它工作得很好。

编辑:

我终于开始清理我的类库了。我添加了一些新功能并创建了一个文档齐全的演示 Web 应用程序。

所有这些都托管在 CodePlex 上。我希望这可以帮助别人。

于 2009-09-16T18:48:31.093 回答
0

我绝不是专家,但如果您对 ASP.NET MVC 非常陌生,那么我建议您先从内置功能开始,然后再自行开发。它完成了您所描述的大部分工作,除了不鼓励在控制器中定义/构造 UI,因为这是视图的工作。

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

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

要专门解决您的编辑:

第 1 步到第 1 步是违反 MVC 范式的。第四步,好。步骤 5 到 7 几乎是标准的 MVC 实践,并得到框架的完全支持。例如,Performing Simple Validation (C#)显示了验证和错误消息显示的示例。

于 2009-06-24T19:42:29.413 回答
0

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

由于 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;
    }
于 2009-06-24T21:02:00.237 回答
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

于 2009-06-24T21:50:06.487 回答