【问题标题】:ASP.NET MVC Model Binding with Dashes in Form Element NamesASP.NET MVC 模型与表单元素名称中的破折号绑定
【发布时间】:2012-06-25 18:25:38
【问题描述】:

我一直在互联网上搜索,试图找到一种方法将我的表单元素中的破折号容纳到 MVC 2、3 甚至 4 中 ASP.NET 控制器的默认模型绑定行为中。

作为一名前端开发人员,我更喜欢 CSS 中的破折号,而不是 camelCase 或下划线。在我的标记中,我希望能够做的是这样的事情:

<input type="text" name="first-name" class="required" />
<input type="text" name="last-name" class="required" />

在控制器中,我将传入一个如下所示的 C# 对象:

public class Person
{
      public string FirstName { get; set; }
      public string LastName { get; set; }
      //etc...
}

有没有办法扩展Controller 类以通过一些正则表达式或其他行为来适应这种情况?我讨厌我必须做这样的事情:

<input type="text" name="person.firstname" class="required" />

甚至这个:

<input type="text" name="isPersonAttending" class="required" />

想法?

【问题讨论】:

标签: c# asp.net-mvc model-view-controller model-binding


【解决方案1】:

对于寻找 ASP.NET Core 解决方案的读者,请尝试[From...] 属性之一。例如:

public class Person
{
    [FromForm(Name = "first-name")]
    public string FirstName { get; set; }
    [FromForm(Name = "last-name")]
    public string LastName { get; set; }
    //etc...
}

[From...] 属性在https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1#sources 上有简要说明。

【讨论】:

    【解决方案2】:

    通过创建自定义表单值提供程序,您可以轻松解决此问题。另一个优点是您可以通过装饰自定义属性来避免污染所有模型属性。

    自定义表单值提供者

    public class DashFormValueProvider : NameValueCollectionValueProvider
    {
        public DashFormValueProvider(ControllerContext controllerContext)
        : base(controllerContext.HttpContext.Request.Form, 
        controllerContext.HttpContext.Request.Unvalidated().Form, 
        CultureInfo.CurrentCulture)
        {
        }
    
        public override bool ContainsPrefix(string prefix)
        {
            return base.ContainsPrefix(GetModifiedPrefix(prefix));
        }
    
        public override ValueProviderResult GetValue(string key)
        {
            return base.GetValue(GetModifiedPrefix(key));
        }
    
        public override ValueProviderResult GetValue(string key, bool skipValidation)
        {
            return base.GetValue(GetModifiedPrefix(key), skipValidation);
        }
    
        // this will convert the key "FirstName" to "first-name".
        private string GetModifiedPrefix(string prefix)
        {
            return Regex.Replace(prefix, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1-").ToLower();
        }
    }
    

    价值提供者工厂

    public class DashFormValueProviderFactory : ValueProviderFactory
    {
        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
    
            return new DashFormValueProvider(controllerContext);
        }
    }
    

    Global.asax.cs

    ValueProviderFactories.Factories.Add(new DashFormValueProviderFactory());
    

    【讨论】:

    • 不错!我同意你的看法——如果你的大多数表单元素名称都使用破折号,那么使用属性会有点多。感谢分享!
    【解决方案3】:

    您始终可以创建自己的模型绑定器。

    这是一个实现支持将别名添加到模型属性的绑定器的示例:

    http://ole.michelsen.dk/blog/bind-a-model-property-to-a-different-named-query-string-field/

    然后用它做类似的事情:

    [ModelBinder(typeof(AliasModelBinder))]
    public class Person
    {
          [BindAlias("first-name")]
          public string FirstName { get; set; }
          [BindAlias("last-name")]
          public string LastName { get; set; }
          //etc...
    }
    

    编辑: 正如博主所说,此实现基于 Andras 对以下 SO 问题的回答: Asp.Net MVC 2 - Bind a model's property to a different named value

    【讨论】:

    • 请注意,正如博客作者所说,这是我自己的答案的副本:stackoverflow.com/questions/4316301/…
    • 这是合乎逻辑的并且非常有意义。谢谢!
    • 安德拉斯,你是完全正确的,我没有看到你的答案的参考。对于那个很抱歉。顺便说一句,很好的实现。
    • 嗨@pabloromeo 别担心,这很酷,谢谢 :-) 很高兴看到它正在帮助他人!
    • 没有问题。我刚刚也添加了对您答案的引用;)
    猜你喜欢
    • 2013-06-11
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    • 2016-03-18
    • 2013-02-04
    • 2014-01-19
    • 2012-11-13
    相关资源
    最近更新 更多