ASP.NET MVC - 值类型的自定义验证消息

时间:2009-03-14 17:07:56

标签: asp.net-mvc validation

当我使用UpdateModel或TryUpdateModel时,MVC框架足够聪明,可以知道您是否尝试将null传入值类型(例如,用户忘记填写所需的Birth Day字段)。

不幸的是,我不知道如何覆盖默认消息“需要一个值”。在总结中更有意义(“请输入您的出生日”)。

必须有一种方法可以做到这一点(没有编写过多的解决方法),但我找不到它。有什么帮助吗?

修改

此外,我想这对于无效转换也是一个问题,例如: BirthDay =“你好”。

7 个答案:

答案 0 :(得分:19)

通过扩展DefaultModelBinder创建自己的ModelBinder:

public class LocalizationModelBinder : DefaultModelBinder

覆盖SetProperty:

        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);

        foreach (var error in bindingContext.ModelState[propertyDescriptor.Name].Errors.
            Where(e => IsFormatException(e.Exception)))
        {
            if (propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)] != null)
            {
                string errorMessage =
                    ((TypeErrorMessageAttribute)propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)]).GetErrorMessage();
                bindingContext.ModelState[propertyDescriptor.Name].Errors.Remove(error);
                bindingContext.ModelState[propertyDescriptor.Name].Errors.Add(errorMessage);
                break;
            }
        }

添加函数bool IsFormatException(Exception e)以检查Exception是否是FormatException:

if (e == null)
            return false;
        else if (e is FormatException)
            return true;
        else
            return IsFormatException(e.InnerException);

创建一个Attribute类:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
public class TypeErrorMessageAttribute : Attribute
{
    public string ErrorMessage { get; set; }
    public string ErrorMessageResourceName { get; set; }
    public Type ErrorMessageResourceType { get; set; }

    public TypeErrorMessageAttribute()
    {
    }

    public string GetErrorMessage()
    {
        PropertyInfo prop = ErrorMessageResourceType.GetProperty(ErrorMessageResourceName);
        return prop.GetValue(null, null).ToString();
    }
}

将属性添加到您要验证的属性:

[TypeErrorMessage(ErrorMessageResourceName = "IsGoodType", ErrorMessageResourceType = typeof(AddLang))]
    public bool IsGood { get; set; }

AddLang是一个resx文件,IsGoodType是资源的名称。

最后将其添加到Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder();

干杯!

答案 1 :(得分:6)

使用DefaultModelBinder可以覆盖默认的必需错误消息,但遗憾的是它将全局应用,恕我直言使其完全无用。但如果你决定这样做,那就是:

  1. 将App_GlobalResources文件夹添加到ASP.NET站点
  2. 添加名为Messages.resx
  3. 的资源文件
  4. 在资源文件中声明一个新的字符串资源,其中包含键PropertyValueRequired和一些值
  5. 在Application_Start中添加以下行:

    DefaultModelBinder.ResourceClassKey = "Messages";
    
  6. 正如您所看到的,您要验证的模型属性与错误消息之间没有任何关联。

    总之,最好编写自定义验证逻辑来​​处理这种情况。一种方法是使用可空类型(System.Nullable< TValueType>)然后:

    if (model.MyProperty == null || 
        /** Haven't tested if this condition is necessary **/ 
        !model.MyProperty.HasValue)
    {
        ModelState.AddModelError("MyProperty", "MyProperty is required");
    }
    

答案 2 :(得分:4)

我一直在使用令人敬畏的xVal验证框架。它允许我在模型中进行所有验证(甚至LINQ-SQL :))。它还会发出客户端验证所需的javascript。

编辑:抱歉遗漏了link,了解如何使其适用于LINQ-SQL

基本工作流程就是这样的。

public partial class YourClass
{
    [Required(ErrorMessage = "Property is required.")]
    [StringLength(200)]
    public string SomeProperty{ get; set; }
}

try
{
    // Validate the instance of your object
    var obj = new YourClass() { SomeProperty = "" }
    var errors = DataAnnotationsValidationRunner.GetErrors(obj);
    // Do some more stuff e.g. Insert into database
}
catch (RulesException ex)
{
    // e.g. control name 'Prefix.Title'
    ex.AddModelStateErrors(ModelState, "Prefix");   
    ModelState.SetModelValue("Prefix.Title", new ValueProviderResult(ValueProvider["Prefix.Title"].AttemptedValue, collection["Prefix.Title"], System.Globalization.CultureInfo.CurrentCulture));

}

答案 3 :(得分:3)

怎么样?

[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$",
                   ErrorMessage = "Characters are not allowed.")]

这应该允许您为要使用的任何MVC验证器标记具有特定错误消息的属性...

答案 4 :(得分:2)

在ASP.NET MVC 1中,我也遇到了这个问题。

在我的项目中,有一个名为“Entry”的模型或业务对象,其主键EntryId是int? type,并且EntryId的值可以允许用户输入。

所以问题是,当字段为空或零或存在一些整数值时,自定义错误消息可以很好地显示,但如果值是某个非整数值,如“a”,我不能找到一种方法来使用自定义消息来替换默认消息,例如“值'a'无效”。

当我在ModelState中跟踪错误消息时,我发现当值为非整数时,会有两个与EntryId相关的错误,并且第一个项目的错误消息为空白...

现在我必须使用这样一个丑陋的代码来解决这个问题。

if (ModelState["EntryId"].Errors.Count > 1)
{
    ModelState["EntryId"].Errors.Clear(); //should not use ModelState["EntryId"].remove();
    ModelState.AddModelError("EntryId", "必须为大于0的整数"); //必须为大于0的整数 means "it should be an integer value and great than 0"
}  

但这会使控制器变胖,希望有一个真正的解决方案来解决它。

答案 5 :(得分:1)

查找ModelState.AddError

答案 6 :(得分:0)

是的,有一种方法,您必须将 System.ComponentModel.DataAnnotations xVal 结合使用,您将能够设置验证规则和消息(你甚至可以使用属性
为每个属性使用资源文件进行本地化 查看此处 http://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/