【问题标题】:Uppercase attribute that converts the input to uppercase将输入转换为大写的大写属性
【发布时间】:2013-07-16 07:16:20
【问题描述】:

我在 MVC4 中工作,想使用 Uppercase 属性定义模型。想法是,Uppercase 属性的存在会导致模型值在到达服务器时转换为大写。

目前我在模型中有以下代码:

    [Required]
    [Display(Name="Account Code")]
    [StringValidation(RegExValidation.AccountCode, Uppercase=true)]
    public string Account
    {
        get { return _account; }
        set
        {
            if (value != null)
                _account = value.ToUpper();
        }
    }

但我真正想要的是:

    [Required]
    [Display(Name="Account Code")]
    [StringValidation(RegExValidation.AccountCode)]
    [Uppercase]
    public string Account { get; set; }

我认为我可能需要将大写属性创建为ValidationAttribute,以确保在模型访问服务器时触发它。但这似乎有点错误,因为我并没有真正验证数据。有没有更好的办法?

另外,有什么方法可以保证属性的调用顺序?我真的想在自定义 StringValidation 属性触发之前将数据转换为大写,因为这会检查正则表达式模式中文本的大小写。

要为此添加一点背景,我想减少添加代码以大写数据的需要。必杀技将是一个单一属性,它在模型绑定或验证阶段更新进入服务器的数据。然后可以在 StringValidation 属性中引用此属性,以修改其检查中使用的 RegEx 值。然后,我还可以在自定义的 TextBoxFor 辅助方法中查找此属性,这样我就可以添加 text-transform: uppercase,使其在客户端看起来正确。

有人有什么想法吗?

【问题讨论】:

    标签: asp.net-mvc custom-attributes data-annotations


    【解决方案1】:

    我已经设法让这个工作达到一定程度,所以这是我的解决方案供其他人评估。

    有一点需要注意的是,由于我无法在StringValidation.IsValid() 属性中获取Modelmetadata,因此无法实现完整的解决方案。我在这里遇到的特殊问题是我可以获取元数据,但是我无法从中获取PropertyName,只能获取DisplayName。有多种选择,但我的一些属性具有相同的 DisplayName 这一事实意味着我无法确定 ProprtyName 是我实际验证的那个。

    这是ValidationAttribute的代码:

    public class StringValidationAttribute : ValidationAttribute, IClientValidatable, IMetadataAware {
    
        private bool _uppercase;
    
        public StringValidationAttribute(bool uppercase = false) {
             _uppercase = uppercase;
        }
    
        ...
    
        public void OnMetadataCreated(ModelMetadata metadata)
        {
            metadata.AdditionalValues["Uppercase"] = _uppercase;
        }
    }
    

    然后我创建了一个新的IModelBinder 实现:

    public class StringBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {           
            ValueProviderResult result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    
            if (result == null)
                return null;
    
            if (bindingContext.ModelMetadata.AdditionalValues.ContainsKey("Uppercase")) {
                if ((bool)bindingContext.ModelMetadata.AdditionalValues["Uppercase"]])
                    return result.AttemptedValue.ToUpper();
            }
    
            return result.AttemptedValue;
        }
    }
    

    并在 myGlobal.asax 文件中注册:

    ModelBinders.Binders.Add(typeof(string), new StringBinder());
    

    如果在模型上附加了StringValidationAttribute,并且设置了大写指示符,那么到目前为止的代码将导致进入MVC的任何字符串输入转换为大写。

    接下来,为了实现将 html 表单也设为大写的愿望,我实现了一个名为 string.cshtml 的新 EditorTemplate。在这个视图中我添加了:

    RouteValueDictionary htmlAttributes = new RouteValueDictionary();
    if ((bool)ViewData.ModelMetadata.AdditionalValues["Uppercase"]) {
        htmlAttributes.Add("class", "Uppercase");
    }
    @Html.TextBox("", Model, htmlAttributes)
    

    以 CSS 作为;

    .Uppercase {
        text-transform: uppercase;
    }
    

    希望这篇文章对其他人有所帮助。

    【讨论】:

    • 嗨,这适用于 MVC 4 吗?因为我收到以下错误。 'UpperCaseValidationAttribute' 没有实现接口成员 'System.Web.Mvc.IClientValidatable.GetClientValidationRules(System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext)' 你能帮忙吗?谢谢!!
    • 是的,这适用于 MVC4。您需要为public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 添加一个覆盖。这是答案中...中的一点:)
    • 它是否以大写形式将文本存储在数据库中? @尼克
    • 就控制器所知,文本始终以大写形式显示。假设您将其直接传递给数据库,那么它会以大写形式命中数据库。
    【解决方案2】:

    对于 Web API 而言,最好将传入的 json 转换为大写或小写。

        public class ToUpperCase : JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return objectType == typeof(string);
            }
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                return reader.Value.ToString().ToUpper();
            }            
        }
    
    
    
        [Display(Name = "PNR NAME")]
        [JsonConverter(typeof(Annotations.ToUpperCase))]
        public string PNR { get; set; }
    

    或全局;

      protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            //.......... others
    
    
    
            JsonMediaTypeFormatter jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
            JsonSerializerSettings jSettings = new Newtonsoft.Json.JsonSerializerSettings();
            jSettings.Converters.Add(new UpperCaseStringConverter());
            jsonFormatter.SerializerSettings = jSettings;
        }
    

    【讨论】:

      【解决方案3】:

      你说得对,ValidationAttribute 不合适。在模型绑定阶段这样做似乎是一个更好的主意。有关如何自定义此行为的详细说明,请参阅 this article

      根据那里提供的信息,我相信您应该能够像这样基于CustomModelBinderAttribute 创建一个属性:

      [AttributeUsage(AttributeTargets.Property)]
      public class UppercaseAttribute : CustomModelBinderAttribute
      {
          public override IModelBinder GetBinder()
          {
              return new UppercaseModelBinder();
          }
      
          private class UppercaseModelBinder : DefaultModelBinder
          {
              public override object BindModel(
                  ControllerContext controllerContext,
                  ModelBindingContext bindingContext)
              {
                  var value = base.BindModel(controllerContext, bindingContext);
                  var strValue = value as string;
                  if (strValue == null)
                      return value;
                  return strValue.ToUpperInvariant();
              }
          }
      }
      

      我没有测试过这个。让我知道它是否有效。

      【讨论】:

      • 感谢 Daniel,遗憾的是 DefaultModelBinder 无法分配给属性。 AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Struct|AttributeTargets.Enum|AttributeTargets.Interface|AttributeTargets.Parameter
      • 那么我们将不得不上一层楼。我们需要为包含这些字符串的类更改模型绑定器,将 UppercaseAttribute 更改为简单的标记属性,并告诉模型绑定器查找此属性并以不同方式处理这些字符串。
      【解决方案4】:

      注意: 我在这篇文章中添加了内容,因为在我发现我现在使用的方法之前,我阅读了这篇文章并尝试了上述所有方法,但均未成功。

      在处理强制将文本数据格式化为大写时,我通常使用两部分过程。 1. 在视图和 2. 在控制器

      1. 在视图层,以便用户知道数据将以大写形式使用。这可以通过 EditorFor HTML 帮助器中使用的 htmlAttributes 来实现。

        @HTML.EditorFor(model => model.Access_Code, new { htmlAttributes = new  Style= "text-transform:uppercase"}})
        

      现在这只会强制用户看到和输入的数据为大写,而不是发送到服务器的数据。为此,需要在控制器的关联方法中添加一些代码。

      1. 我将 ToUpper() 方法添加到传递回控制器的对象的目标属性。这是显示这一点的假设示例。

        public ActionResult verify(int? id)
              {
                var userData = db.user.Where (i=> i.userID == id).Single();
        
                userData.Access_Code = userData.Access_Code.ToUpper();
        
           ...
         }
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 2018-12-17
        • 2020-04-07
        • 2011-10-29
        • 1970-01-01
        • 2011-07-21
        相关资源
        最近更新 更多