2010-11-08 4 views
2

J'ai un formulaire MVC 2 assez simple. Il a deux listes déroulantes, utilisateur et rôle. La liste déroulante des employés passe la validation, et la liste déroulante des rôles ne le fait pas, indépendamment de ce que je sélectionne. Il n'y a pas d'option "vide" par défaut bien que je prévoie d'en implémenter une, c'est pourquoi j'ai besoin que la validation fonctionne. Il échoue à la fois la validation du client et du serveur. Je ne vois pas pourquoi on travaillerait et on ne le ferait pas!ModelState.IsValid renvoie false quand il devrait être vrai

Le formulaire:

<% using (Html.BeginForm()) {%> 

    <%:Html.ValidationSummary(true) %> 
    <%:Html.EditorFor(model => model.User, new { AllEmployees = Model.AllEmployees, RoleList = Model.RoleList })%> 

    <p> 
     <input type="submit" value="Add New User" /> 
    </p> 

    <% } %> 

<% Html.EndForm(); %> 

Le modèle Editeur:

<tr> 
    <td> 
     <div class="editor-label"> 
      <%: Html.LabelFor(model => model.UserId) %> 
      <%: Html.RequiredMarkFor(model => model.UserId) %> 
     </div> 
    </td>  
    <td>  
    <div class="editor-field"> 
     <%: Html.DropDownListFor(model => model.UserId, new SelectList(ViewData["AllEmployees"] as IEnumerable, "UserId", "DisplayName", Model.UserId)) %> 
     <%: Html.ValidationMessageFor(model => model.UserId> 
    </div>  
    </td>  
</tr>  

<tr> 
    <td> 
     <div class="editor-label"> 
      <%: Html.LabelFor(model => model.AccessLevel)%> 
      <%: Html.RequiredMarkFor(model => model.AccessLevel)%> 
     </div> 
    </td>  
    <td>  
     <div class="editor-field"> 
      <%: Html.DropDownListFor(model => model.AccessLevel, new SelectList(ViewData["RoleList"] as IEnumerable, Model.AccessLevel))%> 
      <%: Html.ValidationMessageFor(model => model.AccessLevel)%> 
     </div>  
    </td>  
</tr> 

Les métadonnées:

[DisplayName("Employee")] 
    [Required(ErrorMessage = "Please select an employee.")] 
    [StringLength(8, ErrorMessage = "User Id must be less than 8 characters.")] 
    [DisplayFormat(ConvertEmptyStringToNull = false, 
          HtmlEncode = true)] 
    [DataType(DataType.Text)] 
    public object UserId { get; set; } 


    // Validation rules for Access Level 
    [DisplayName("Role")] 
    [Required(ErrorMessage = "Please select the role for this user.")] 
    [StringLength(15, ErrorMessage = "Role must be under 15 characters.")] 
    [DisplayFormat(ConvertEmptyStringToNull = false, 
          HtmlEncode = true)] 
    [DataType(DataType.Text)] 
    public object AccessLevel { get; set; } 

L'action Get:

List<String> roles = (from o in txDB.Users 
             select o.AccessLevel).Distinct().ToList(); 

    var viewModel = new UserViewModel 
    { 
     User = new User(), 
     AllEmployees = empList, 
     RoleList = roles 
    }; 
    return View(viewModel); 

L'Action Post:

[HttpPost] 
    [AuthorizeAttribute(Roles="Administrator")] 
    public ActionResult Create(User user) 
    { 
     if(!ModelState.IsValid) 
     { 
      //ModelState is invalid 
      return View(new User()); 
     } 
     try 
     { 
      //do stuff 
     } 
    } 

L'assistant requis Méthode (de Define markup for [Required] fields in View in ASP.NET MVC 2.0):

public static string RequiredMarkFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression) 
    { 
     if(ModelMetadata.FromLambdaExpression(expression, helper.ViewData).IsRequired) 
      return "*"; 
     else 
      return string.Empty; 
    } 

Répondre

2

méthode post devrait être comme suit pour obtenir la validation côté serveur ...

[HttpPost] 
[AuthorizeAttribute(Roles="Administrator")] 
public ActionResult Create(User user) 
{ 
    if(!TryUpdateModel(user)) 
    { 
     // Model is INVALID 
     return View(user); 
    } 
    else 
    { 
     // ModelState is VALID 
     // Do stuff 
    } 
} 

Le else pourrait être redondant en fonction de ce que vous faites, mais que vous devriez y aller. Dans la vue au dessus de votre <% using Html.BeginForm() %> vous avez besoin

<% Html.EnableClientValidation(); %> 

Vous devez également référencer les scripts, MicrosoftAjax et MicrosoftMvcValidation je pense

+0

Comment TryUpdateModel fonctionne-t-il en référence à ModelState? Et oui, tous les scripts sont référencés et la validation du client ajoutée, ne l'affiche pas dans le code. – morganpdx

+0

Ok, je n'ai pas vu le code, donc je ne voulais pas supposer. TryUpdateModel est juste une méthode que j'ai constamment utilisée depuis que quelqu'un me l'a suggéré ici. –

1

d'abord: Vous avez deux balises de formulaire de fermeture

Si vous utilisez

<% using (Html.BeginForm()) {%> 
<% } %> 

vous n'avez pas besoin de l'utiliser

<% Html.EndForm(); %> 

En ce qui concerne votre problème de validation que vous utilisez un éditeur uniquement pour votre propriété de l'utilisateur, qui est le seul qui se binded par le liant modèle

<%:Html.EditorFor(model => model.User, new { AllEmployees = Model.AllEmployees, RoleList = Model.RoleList })%> 

Essayez de remplacer le code précédent avec un EditorForModel en tant que votre modèle d'éditeur est pour une classe de modèle.

Ainsi, votre formulaire doit changer

<% using (Html.BeginForm()) {%> 

    <%:Html.ValidationSummary(true) %> 
    <table> 
     <%:Html.EditorForModel()%> 
    </table> 
    <p> 
     <input type="submit" value="Add New User" /> 
    </p> 
<% } %> 

et vous avez terminé!

+0

Le but d'utiliser l'éditeur uniquement pour l'utilisateur est parce que la vue utilise une viewmodel en afin de me permettre de passer les deux listes déroulantes. Est-ce que vous suggérez que je tape juste fortement la vue à l'utilisateur, et transmettez les listes dans les viewdata? – morganpdx

+0

Votre vue est fortement typée au ViewModel. Votre EditorTemplate crée un balisage html pour la liste déroulante. Si vous utilisez juste 'Html.EditorFor (model => model.User ...'vous indiquez à la vue de lier une propriété à la vue même si vous passez tout le modèle de vue. – Lorenzo

+0

J'ai essayé cela - même effet. En passant, merci de signaler la redondance EndForm, n'a pas remarqué cela. D'autres idées? Je suis sur le point de simplement commenter l'annotation [Obligatoire] et de continuer: P – morganpdx

Questions connexes