2009-03-14 20 views
23

Cuando uso UpdateModel o TryUpdateModel, la estructura MVC es lo suficientemente inteligente como para saber si está intentando pasar un valor nulo a un tipo de valor (por ejemplo, el usuario se olvida de completarlo el campo requerido del Día de nacimiento).ASP.NET MVC - Mensaje de validación personalizado para los tipos de valor

Desafortunadamente, no sé cómo sobrescribir el mensaje predeterminado, "Se requiere un valor". en el resumen en algo más significativo ("Por favor ingrese en su día de nacimiento").

Tiene que haber una forma de hacerlo (sin escribir demasiado código de trabajo), pero no puedo encontrarlo. ¿Alguna ayuda?

EDITAR

Además, supongo que esto también sería un problema para las conversiones no válidas, por ejemplo, BirthDay = "Hola".

Respuesta

1

Buscar ModelState.AddError.

+0

Conozco ModelState.AddModelError(), pero UpdateModel() agrega automáticamente valores a la colección de errores. ¿A menos que malinterprete tu respuesta? –

+1

Bueno, cuando valide, agregue algo al ModelState. Aquí hay un gran tutorial. http://blog.maartenballiauw.be/post/2008/08/29/Form-validation-with-ASPNET-MVC-preview-5.aspx –

+0

Tenía la esperanza de no tener que atar todo yo solo, pero tal vez sea la única manera si quiero mis propios mensajes? –

4

He estado usando el impresionante marco de validación xVal. Me permite hacer toda mi validación en el modelo (Even LINQ-SQL :)). También emite el javascript requerido para la validación del lado del cliente.

EDIT: Lo sentimos dejado fuera del link de cómo conseguir que funcione para LINQ-SQL

El flujo de trabajo básico es algo como esto.

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)); 

} 
+0

Solo para el registro, xVal está en desuso [según] (http://xval.codeplex.com/) para el equipo xVal. Solo recomiendan que lo use con MVC 1.0, y ya no se mantiene o desarrolla activamente. –

6

Con la DefaultModelBinder es posible anular el mensaje de error predeterminado requerido pero, desgraciadamente, se aplicaría a nivel mundial, que en mi humilde opinión la hace completamente inútil. Pero en caso de que decida hacerlo aquí cómo:

  1. agregar la carpeta App_GlobalResources a su sitio ASP.NET
  2. añadir un archivo llamado Messages.resx recursos
  3. Dentro del archivo de recursos declarar un nuevo recurso de cadena con la llave y PropertyValueRequired algún valor
  4. En Application_Start añadir la siguiente línea:

    DefaultModelBinder.ResourceClassKey = "Messages"; 
    

Como puede ver, no hay ningún enlace entre la propiedad del modelo que está validando y el mensaje de error.

En conclusión, es mejor escribir una lógica de validación personalizada para manejar este escenario. Una forma sería utilizar un tipo anulable (System.Nullable <TValueType>) y luego:

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

¿sabe si el comportamiento de ResourceClassKey ha cambiado últimamente? Esto parece estar roto en MVC 3. El doc incluso dice que debería arrojar una excepción para una clase no válida, pero no lo hará, incluso si lo hago DefaultModelBinder.ResourceClassKey = "lkjhjkjdswqq". –

+0

nevermind ... acabo de encontrar su respuesta en http://stackoverflow.com/questions/5395040/globally-localize-validation/5395297#5395297 con la cita de Brad sobre por qué esto no funciona :) –

3

¿qué tal esto?

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

que debe permitir etiquetar propiedades con mensajes de error específicos para cualquier MVC validadores que desea utilizar ...

2

En ASP.NET MVC 1, me encontré con este problema también.

En mi proyecto, hay un objeto de modelo o de negocio llamado "Entrada", y su clave principal EntryId es int? escriba, y el valor de EntryId puede ser permitido por los usuarios.

Así que el problema es que cuando el campo está en blanco o cero o algún valor entero que haya existido, los mensajes de error personalizados se pueden mostrar bien, pero si el valor es un valor no entero como "a", puedo no encuentre una forma de utilizar el mensaje personalizado para reemplazar el mensaje predeterminado como "El valor 'a' no es válido".

Cuando rastreo del mensaje de error en ModelState, encontré cuando el valor no es entero, habrá dos errores relacionados con ENTRYID, y el mensaje de error del primer elemento está en blanco ...

Ahora tengo usar un código tan feo para hackear el problema.

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" 
} 

pero esto hace que el controlador sea gordo, espero que haya una solución real para resolverlo.

19

Haga su propio ModelBinder extendiendo DefaultModelBinder:

public class LocalizationModelBinder : DefaultModelBinder 

Anulación 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; 
      } 
     } 

Añadir la función bool IsFormatException(Exception e) para comprobar si una excepción es un FormatException:

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

crear una clase Atributo:

[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(); 
    } 
} 

Añadir el atributo de la propiedad que desea validar:

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

AddLang es un archivo resx y IsGoodType es el nombre del recurso.

Y por último añadir esto en Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder(); 

Salud!

+4

Gran respuesta, pero hay una problema con eso. 'propertyDescriptoy.Name' no siempre se utiliza como la clave para' ModelState'. En su lugar, debe usar el método heredado 'CreateSubPropertyName' para crear la clave, así:' ModelMetadata propertyMetadata = bindingContext.PropertyMetadata [propertyDescriptor.Name]; string propertyName = CreateSubPropertyName (bindingContext.ModelName, propertyMetadata.PropertyName); 'y luego puede usar' bindingContext.ModelState [propertyName] 'en su lugar. – Iravanchi

+2

Ow, ... y 'GetErrorMessage' en la clase de atributo debería devolver' ErrorMessage' en caso de que no esté vacío (o al revés). No tiene en cuenta el caso de que el usuario del atributo especifique el mensaje de error en línea (sin ningún recurso). – Iravanchi

Cuestiones relacionadas