【问题标题】:Advice with Dynamic Forms in ASP.NET MVC在 ASP.NET MVC 中使用动态表单的建议
【发布时间】:2009-06-24 19:38:46
【问题描述】:

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

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

我正在考虑创建一个自定义模型绑定器来实现这一点。我通常打算这样做:

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

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

【问题讨论】:

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


    【解决方案1】:

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

    编辑:

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

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

    【讨论】:

    • 我想我已经分享了这个想法。但是,我也不介意分享代码。等待链接。
    • mvcdynamicforms.codeplex.com - 没有示例,没有文档,只有代码。我会尝试发布文档和示例。
    • 谢谢,即使没有文档,代码也非常简单,它确实帮助我解决了相关问题。 +1
    • 很高兴它有帮助。该库的源代码确实是一团糟。这周我一直在重构它并清理它。我还继续创建了一个基本的演示 mvc 应用程序。这个周末我应该可以在 codeplex 网站上发布我的新作品了。
    • 太棒了。我真的迟早会用更简洁的代码发布这个。
    【解决方案2】:

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

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

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

    专门针对您的编辑:

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

    【讨论】:

    • 是的,但这仅适用于使用 HtmlHelper 创建的字段输入,并且我需要呈现的许多类型的字段不支持开箱即用(复选框列表、单选列表、列表框)。
    • 确实有困难。我会扩展 HtmlHelper 以便它正确地支持它们,这样做的代码并不是很复杂。现在我使用我自己的 Utility 类来处理这些,因为我还没有处理任何更复杂的东西。我真的不明白 MVC 中缺乏对这些输入类型的适当支持:[
    • 回应您的更新:我已经问过这个问题。我正在使用 MVC,因为我 99% 的应用程序都非常适合 MVC。但是应用程序的这一小部分需要动态生成表单。我还不习惯混合 webforms 和 mvc,所以我想尝试在 MVC 中做到这一点。另外,我看不出我计划做的任何事情会如何颠覆 SOC 或对 HTML 的控制。
    • 关于 SOC,我假设您的第 3 步是您通过自定义模型绑定器编写的一些代码,并自动为您的表单字段生成所有 HTML。这不是你的意思吗?
    • 没有。我的计划不是让模型绑定器与呈现 HTML 有任何关系。相反,FieldDefinition(步骤 1)对象将负责呈现其 HTML。另外,我打算从 View 模板中调用 FieldDefiniton 的 RenderHtml 方法。
    【解决方案3】:

    虽然不是专家,但我必须创建一个解决方案,其中我的主要对象有一个值列表。让我们称之为对象 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;
        }
    

    【讨论】:

      【解决方案4】:

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

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

      本文使用 Code dom 生成 ActionLink。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-18
        • 2023-03-28
        • 2012-03-26
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        • 2011-01-14
        • 1970-01-01
        相关资源
        最近更新 更多