web-dev-qa-db-fra.com

ASP.NET MVC - Message de validation personnalisé pour les types de valeur

Lorsque j'utilise UpdateModel ou TryUpdateModel, le framework MVC est suffisamment intelligent pour savoir si vous essayez de passer un null à un type de valeur (par exemple, l'utilisateur oublie de renseigner le champ requis du jour de naissance).

Malheureusement, je ne sais pas comment remplacer le message par défaut, "Une valeur est requise". dans le résumé en quelque chose de plus significatif ("S'il vous plaît entrez dans votre jour de naissance").

Il doit y avoir un moyen de le faire (sans écrire trop de code de contournement), mais je ne le trouve pas. De l'aide?

MODIFIER

De plus, je suppose que cela poserait également un problème pour les conversions non valides, par exemple. BirthDay = "Bonjour".

23
Giovanni Galbo

Créez votre propre ModelBinder en étendant DefaultModelBinder:

public class LocalizationModelBinder : DefaultModelBinder

Remplacer 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;
            }
        }

Ajoutez la fonction bool IsFormatException(Exception e) pour vérifier si une exception est une exception FormatException:

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

Créez une classe d'attribut:

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

Ajoutez l'attribut à la propriété que vous souhaitez valider:

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

AddLang est un fichier resx et IsGoodType est le nom de la ressource.

Et ajoutez enfin ceci dans Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder();

À votre santé!

19
Cristi Todoran

Avec DefaultModelBinder, il est possible de remplacer le message d'erreur requis par défaut, mais malheureusement, il s'appliquerait globalement, quel IMHO le rend complètement inutile. Mais si vous décidez de le faire, voici comment:

  1. Ajouter le dossier App_GlobalResources à votre site ASP.NET
  2. Ajouter un fichier de ressources appelé Messages.resx
  3. Dans le fichier de ressources, déclarez une nouvelle ressource de chaîne avec la clé PropertyValueRequired et une valeur
  4. Dans Application_Start, ajoutez la ligne suivante:

    DefaultModelBinder.ResourceClassKey = "Messages";
    

Comme vous pouvez le constater, il n'y a pas de lien entre la propriété de modèle que vous validez et le message d'erreur.

En conclusion, il est préférable d'écrire une logique de validation personnalisée pour gérer ce scénario. Une solution consisterait à utiliser un type nullable (System.Nullable <TValueType>) puis:

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

J'utilise le cadre génial xVal validation. Cela me permet de faire toute ma validation dans le modèle (même LINQ-SQL :)). Il émet également le javascript requis pour la validation côté client.

EDIT: Désolé, le lien n'a pas été lu pour savoir comment le faire fonctionner pour LINQ-SQL

Le flux de travail de base va quelque chose comme ça.

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

}
4
Alex

que dis-tu de ça?

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

Cela devrait vous permettre de baliser les propriétés avec des messages d'erreur spécifiques pour les validateurs MVC que vous souhaitez utiliser ...

3
Allan Nienhuis

Dans ASP.NET MVC 1, j'ai également rencontré ce problème.

Dans mon projet, il existe un modèle ou un objet métier nommé "Entrée", et sa clé primaire EntryId est int? type, et la valeur de EntryId peut être autorisée par les utilisateurs.

Le problème est donc, lorsque le champ est vide ou zéro ou une valeur entière qui a existé, les messages d'erreur personnalisés peuvent être affichés bien, mais si la valeur est une valeur non-entière comme "un", je ne peux pas trouver un moyen utiliser le message personnalisé pour remplacer le message par défaut tel que "La valeur 'a' n'est pas valide".

lorsque je suis le message d'erreur dans ModelState, j'ai trouvé que la valeur n'est pas un entier, il y aura deux erreurs liées à EntryId et le message d'erreur du premier élément est vide ...

Maintenant, je dois utiliser un code si laid pour pirater le problème.

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

mais cela rend le contrôleur gros, espérons qu'il existe une vraie solution pour le résoudre.

2
user134936

Recherchez ModelState.AddError.

1
Daniel A. White

oui, vous pouvez utiliser System.ComponentModel.DataAnnotationsen combinaison avec xValet vous pourrez définir des règles de validation et des messages (vous pouvez même utiliser des fichiers de ressources pour la localisation) pour chacune de vos propriétés à l'aide d'attributs
regardez icihttp://blog.codeville.net/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/

0
Omu