2013-03-22 2 views
3

Прежде всего, извините за мой английский. Не мой естественный язык.ASP.NET MVC 4: Пропустить проверку в дочернем объекте

У меня есть класс с именем Category, как показано ниже. Обратите внимание, что в этом коде у меня также есть свойство Category, в котором я могу ссылаться на категорию «Отец». Это класс, объявленный внутри класса. Как начало. Итак, этот объект категории «Отец» обладает теми же свойствами «класса, который его объявил».

Требуется имущество Name. Помните это свойство.

public class Category 
{ 
    public int? Id{ get; set; } 

    [DisplayName("Father Category")] //NOT REQUIRED 
    public Category Father { get; set; } 

    [DisplayName("Category")] 
    [Required(ErrorMessage = "Name is required")] //REMEMBER THIS REQUIRED PROPERTY!! 
    public string Name { get; set; } 

    [DisplayName("Status")] 
    public bool Status { get; set; } 

    [DisplayName("Description")] 
    public string Description { get; set; } 
} 

Это мой класс.

Так, в категории View, я могу сделать что-то вроде этого:

Примечание: CompleteEditorFor и CompleteDropDownListFor расширены методы, которые добавляют дополнительные HTML в каждой области, только для настройки макета.

@using (Html.BeginForm(null, null, FormMethod.Post)) 
{ 

    @Html.CompleteEditorFor(x => x.Name) 
    @Html.CompleteEditorFor(x => x.Description) 
    @Html.CompleteEditorFor(x => x.Status) 

    @Html.CompleteDropDownListFor(x => x.Father.Id, ViewData["Categories"], "Id", "Name", "Select...") 

    @Html.SubmitButton() 
} 

Код выше работает только отлично.

Теперь есть проблема:

При нажатии на кнопку Сохранить, это делает HttpPost, и это Action для этого:

(ниже код имеет некоторые измененные строки сообщений и расширенные методы.) (CategoriesBLL класс, который получает категории из базы данных.)

[HttpPost] 
    public ActionResult New(Category item) 
    { 
     ViewData.Add("Categories", CategoriesBLL.select()); 
     try 
     { 
      if (ModelState.IsValid)//PROBLEM IS HERE!!!!!!!!! 
      { 
       if (CategoryBLL.insert(item) != 0) 
       { 

        ViewData.AddSuccess("Some Success Message"); 


        return View(new Category()); 
       } 
       else 
       { 
        ModelState.AddError("Some error message"); 
        return View(item); 
       } 
      } 
      else 
      { 
       ModelState.AddError("Some SERIOUS error message"); 
       return View(item); 
      } 
     } 
     catch (Exception ex) 
     { 
      ModelState.AddError("Some EVEN MORE SERIOUS message"); 
      return View(item); 
     } 

    } 

проблема заключается в if (ModelState.IsValid) линии.

Почему?

Потому что мой класс Category имеет обязательное свойство, называемое Name. Мне не нужно это свойство, чтобы делать то, что я делаю, мне просто нужен Id свойства Father. Я могу получить эту Id в этой строке на Вид:

@Html.CompleteDropDownListFor(x => x.Father.Id, ViewData["Categories"], "Id", "Name", "Select...") 

И это работает.

Но свойство Name - это null, и оно требуется, но оно требуется только в том случае, если я сообщаю класс Child. Не класс Отца.

Я даже не знаю, как искать его на Google или StackOverflow ...

Может кто-нибудь мне помочь?

+0

вы пытались удалить дочерние объекты прежде, чем утвердить или не отправлять их с формой? –

+0

Мне нужно отправить объект отцов, но мне просто нужно 1 свойство, свойство Id. Имя также требуется, но не в этом отце. –

ответ

2

Вам необходимо использовать View Models. Ваша модель просмотра должна содержать все поля, которые вам нужны в представлении, минус свойство Father. Затем в вашем контроллере вам нужно будет сопоставить модель просмотра с вашей моделью.Вы можете легко сделать это с помощью Automapper. (Тем не менее, прямое сопоставление из представления в модель домена не рекомендуется, но что вы будете разбираться позже)

Я знаю, сначала это может выглядеть как перетаскивание, но поверьте мне. Ваше представление не совпадает с вашей моделью домена. Следующее, что вы узнаете, вам понадобится выпадающее меню и другой дополнительный флажок, который у вас нет в вашей модели домена. Кроме того, если вы используете модель просмотра, ваша безопасность будет улучшена. Я расскажу вам об этом, если это будет интересно.

+0

Улучшение безопасности? Я заинтересован! –

+0

Прочтите это http://www.codetunnel.com/blog/post/aspnet-mvc-model-binding-security. Первые 2 параграфа расскажут вам, что может пойти не так. Остальная часть статьи также рекомендуется прочитать. Я видел видео с Трой Хант, где он подробно рассказал об этом, но не может найти его сейчас - ( – trailmax

+0

Да, если ваш проект недолговечен и не будет развиваться в будущем, то переключение всего на возможно, не стоит. Да, вы можете написать мне по электронной почте: trailmax1 в gmail dot com. Я постараюсь ответить на ваши вопросы. – trailmax

2

Возможно, вы захотите рассмотреть возможность создания интерфейса класса IValidatableObject на своей модели вместо декораторов свойств. Если вы действительно хотите использовать декоратор свойств, вы можете использовать его самостоятельно.

+0

Будет ли это изменяться, как я проверяю эту модель, или валидатор ModelState автоматически узнает, что делать? –

1
public class Category : IValidatableObject 
{ 
    public int? Id{ get; set; } 

    [DisplayName("Father Category")] //NOT REQUIRED 
    public Category Father { get; set; } 

    [DisplayName("Category")] 
    [Required(ErrorMessage = "Name is required")] //REMEMBER THIS REQUIRED PROPERTY!! 
    public string Name { get; set; } 

    [DisplayName("Status")] 
    public bool Status { get; set; } 

    [DisplayName("Description")] 
    public string Description { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     var results = new List<ValidationResult>(); 
     if (this.Enable) 
     { 
      Validator.TryValidateProperty(this.Name , 
       new ValidationContext(this, null, null) { MemberName = "Name" }, 
       results); 
      Validator.TryValidateProperty(this.Status, 
       new ValidationContext(this, null, null) { MemberName = "Status" }, 
       results); 
     } 
     return results; 
    } 
} 

public void Validate() 
{ 
     var toValidate = new Category() 
     { 
      Name = "Just a name", 
      Status = true 
     }; 

     bool validateAllProperties = false; 

     var results = new List<ValidationResult>(); 

     bool isValid = Validator.TryValidateObject(
      toValidate, 
      new ValidationContext(toValidate, null, null), 
      results, 
      validateAllProperties); 
} 
+0

Нужно ли писать дополнительный код в контроллере? –

+0

нет, не делаю. Контроллер MVC-стека автоматически проверяет значение IValidatableObject и выполняет проверку для вас. – trailmax

+0

@IamStalker, что с 'public void Validate()' вне класса? Должно ли быть внутри класса? если внутри класса, я не вижу, что его зовут где угодно. – trailmax

0
ModelState.Remove("PropertyNameInModel"); 

или

ModelState.Remove<ViewModel>(x => x.SomeProperty); 
Смежные вопросы