34 votes

DataAnnotation pour la propriété Required

D'abord, il fonctionne, mais aujourd'hui, il a échoué !

C'est ainsi que je définis la propriété date :

[Display(Name = "Date")]
[Required(ErrorMessage = "Date of Submission is required.")]        
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
public DateTime TripDate { get; set; }

Cela a fonctionné dans le passé. Mais aujourd'hui, lorsque j'appelle la même action ApiController :

[HttpPost]
public HttpResponseMessage SaveNewReport(TripLeaderReportInputModel model)

Les rapports de Firebug :

ExceptionMessage:

"Property 'TripDate' on type 'Whitewater.ViewModels.Report.TripLeaderReportInputModel' 
is invalid. Value-typed properties marked as [Required] must also be marked with
[DataMember(IsRequired=true)] to be recognized as required. Consider attributing the 
declaring type with [DataContract] and the property with [DataMember(IsRequired=true)]."

ExceptionType

"System.InvalidOperationException"

Qu'est-ce qui s'est passé ? N'est-ce pas [DataContract] para WCF ? J'utilise le REST WebAPI en MVC4 !

Quelqu'un peut-il nous aider ?

--mise à jour -

J'ai trouvé quelques liens similaires.

MvC 4.0 RTM nous a brisé et nous ne savons pas comment le réparer RSS

--- mettre à jour à nouveau ---

Voici l'en-tête de la réponse HTTP :

Cache-Control   no-cache
Connection  Close
Content-Length  1846
Content-Type    application/json; charset=utf-8
Date            Thu, 06 Sep 2012 17:48:15 GMT
Expires         -1
Pragma          no-cache
Server          ASP.NET Development Server/10.0.0.0
X-AspNet-Version    4.0.30319

En-tête de la demande :

Accept          */*
Accept-Encoding gzip, deflate
Accept-Language en-us,en;q=0.5
Cache-Control   no-cache
Connection          keep-alive
Content-Length  380
Content-Type    application/x-www-form-urlencoded; charset=UTF-8
Cookie          .ASPXAUTH=1FF35BD017B199BE629A2408B2A3DFCD4625F9E75D0C58BBD0D128D18FFDB8DA3CDCB484C80176A74C79BB001A20201C6FB9B566FEE09B1CF1D8EA128A67FCA6ABCE53BB7D80B634A407F9CE2BE436BDE3DCDC2C3E33AAA2B4670A0F04DAD13A57A7ABF600FA80C417B67C53BE3F4D0EACE5EB125BD832037E392D4ED4242CF6
DNT                 1
Host            localhost:39019
Pragma          no-cache
Referer         http://localhost:39019/Report/TripLeader
User-Agent          Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20100101 Firefox/15.0
X-Requested-With    XMLHttpRequest

--- mise à jour ---

J'ai trouvé une solution de fortune. Voir la réponse ci-dessous. Si quelqu'un comprend pourquoi cela fonctionne ou a de meilleures solutions, merci de poster vos réponses. Je vous remercie.

34voto

Blaise Points 1901

D'accord. Mais je n'ai pas tout à fait compris cette chose. Une solution de contournement est trouvée.

En Global.asax :

GlobalConfiguration.Configuration.Services.RemoveAll(
    typeof(System.Web.Http.Validation.ModelValidatorProvider),
    v => v is InvalidModelValidatorProvider);

Je l'ai trouvé dans l'Issue Tracker d'aspnetwebstack. Voici le lien vers la page :

Validation trop agressive pour l'application de [DataMember(IsRequired=true)] aux propriétés obligatoires avec des types de valeur

Si quelqu'un peut nous expliquer pourquoi il en est ainsi, merci de nous faire part de votre point de vue en guise de réponse. Nous vous remercions.

13voto

Blaise Points 1901

J'ai ajouté un ModelValidationFilterAttribute et l'a fait fonctionner :

public class ModelValidationFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            // Return the validation errors in the response body.
            var errors = new Dictionary<string, IEnumerable<string>>();
            //string key;
            foreach (KeyValuePair<string, ModelState> keyValue in actionContext.ModelState)
            {
                //key = keyValue.Key.Substring(keyValue.Key.IndexOf('.') + 1);
                errors[keyValue.Key] = keyValue.Value.Errors.Select(e => e.ErrorMessage);
            }
            //var errors = actionContext.ModelState
            //    .Where(e => e.Value.Errors.Count > 0)
            //    .Select(e => new Error
            //    {
            //        Name = e.Key,
            //        Message = e.Value.Errors.First().ErrorMessage
            //    }).ToArray();

            actionContext.Response =
                actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, errors);
        }
    }
}

Vous pouvez soit ajouter [ModelValidation] sur les actions. Ou l'ajouter dans Global.asax.cs :

GlobalConfiguration.Configuration.Services.RemoveAll(
typeof(System.Web.Http.Validation.ModelValidatorProvider),
v => v is InvalidModelValidatorProvider);

De cette manière, je continue à utiliser l'annotation originale des données.

Référence

10voto

Martin Devillers Points 3539

MISE À JOUR 24-5-2013 : Les InvalidModelValidatorProvider responsable de ce message d'erreur a été supprimée de la pile technologique ASP.NET. Ce validateur s'est avéré causer plus de confusion qu'il n'était censé en résoudre. Pour plus d'informations, voir le lien suivant : http://aspnetwebstack.codeplex.com/workitem/270

Lorsque vous décorez votre classe avec [DataContract] vous devez explicitement décorer les membres que vous souhaitez sérialiser avec l'attribut [DataMember] attribut.

Le problème est que DataContractSerializer ne prend pas en charge le [Required] attribut. Pour les types de référence, nous sommes en mesure de vérifier que la valeur n'est pas nulle après la désérialisation. Mais pour les types de valeur, nous n'avons aucun moyen d'appliquer la règle [Required] sémantique pour les DataContractSerializer sans [DataMember(IsRequired=true)] .

Vous pourriez donc finir par marquer un DateTime como [Required] et s'attendre à une erreur de validation du modèle si le DateTime n'est pas envoyé, mais vous obtiendrez simplement un DateTime.MinValue et aucune erreur de validation.

0voto

Maess Points 2342

Si vous essayez de renvoyer la sortie de votre action au format XML, vous devrez utiliser des contrats de données (DataContracts) car ils sont requis par le sérialiseur par défaut. Je suppose que vous avez précédemment demandé la sortie de votre action en Json, le sérialiseur Json ne nécessite pas de contrats de données. Pouvez-vous poster un fiddle de votre requête ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X