Próbuję użyć środowiska ASP.NET MVC 3 do generowania formularzy ze złożonych, zagnieżdżonych obiektów. Istnieje jedno zachowanie sprawdzania poprawności, które znalazłem nieoczekiwane i nie jestem pewien, czy jest to błąd w DefaultModelBinder czy nie.Sprawdzanie poprawności programu ASP.NET MVC 3 na obiektach zagnieżdżonych nie działa zgodnie z oczekiwaniami - sprawdza dwa razy obiekt podrzędny, a nie obiekt nadrzędny.
Jeśli mam dwa obiekty, pozwala wywołać "rodzic" jeden "OuterObject", a to ma właściwość typu "InnerObject" (dziecko):
public class OuterObject : IValidatableObject
{
[Required]
public string OuterObjectName { get; set; }
public InnerObject FirstInnerObject { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(OuterObjectName) && string.Equals(OuterObjectName, "test", StringComparison.CurrentCultureIgnoreCase))
{
yield return new ValidationResult("OuterObjectName must not be 'test'", new[] { "OuterObjectName" });
}
}
}
Oto InnerObject:
public class InnerObject : IValidatableObject
{
[Required]
public string InnerObjectName { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(InnerObjectName) && string.Equals(InnerObjectName, "test", StringComparison.CurrentCultureIgnoreCase))
{
yield return new ValidationResult("InnerObjectName must not be 'test'", new[] { "InnerObjectName" });
}
}
}
Zauważysz walidację, którą umieściłem na obu .. tylko niektóre sprawdzanie atrapa, aby powiedzieć, że pewna wartość nie może być równa "test".
Oto widok, który będzie wyświetlany w (Index.cshtml):
@model MvcNestedObjectTest.Models.OuterObject
@{
ViewBag.Title = "Home Page";
}
@using (Html.BeginForm()) {
<div>
<fieldset>
<legend>Using "For" Lambda</legend>
<div class="editor-label">
@Html.LabelFor(m => m.OuterObjectName)
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.OuterObjectName)
@Html.ValidationMessageFor(m => m.OuterObjectName)
</div>
<div class="editor-label">
@Html.LabelFor(m => m.FirstInnerObject.InnerObjectName)
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.FirstInnerObject.InnerObjectName)
@Html.ValidationMessageFor(m => m.FirstInnerObject.InnerObjectName)
</div>
<p>
<input type="submit" value="Test Submit" />
</p>
</fieldset>
</div>
}
..i wreszcie jest tu HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new OuterObject();
model.FirstInnerObject = new InnerObject();
return View(model);
}
[HttpPost]
public ActionResult Index(OuterObject model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
return View(model);
}
}
Co znajdziesz to, że gdy model zostanie sprawdzony przez DefaultModelBinder, metoda "Validate" w "InnerObject" zostanie dwukrotnie trafiona, ale metoda "Validate" w "OuterObject" nie zostanie w ogóle trafiona.
Jeśli zdejmiesz obiekt IValidatableObject z "InnerObject", zostanie pobity ten z "OuterObject".
Czy to błąd, czy też powinienem oczekiwać, że zadziała w ten sposób? Jeśli powinienem się tego spodziewać, jaki jest najlepszy sposób obejścia tego problemu?
Dzięki myślałem o tym i będzie pracować dla tej konkretnej sytuacji, ale jak teh przedmiot staje się bardziej skomplikowana, że nie będzie działać. Na przykład, jeśli potrzebuję InnerObject1, SomeString, InnerObject2, SomeOtherString (np. Zagnieżdżone obiekty między innymi właściwościami). – nootn
@nootn Czy próbowałeś [Fluent Validation] (http: // http: //fluentvalidation.codeplex.com/wikipage? title = mvc & referingTitle = Documentation), który jest zaawansowanym sposobem sprawdzania poprawności zależności i zagnieżdżonych reguł sprawdzania poprawności? – amythn04
Zajrzałem do tego i wygląda ładnie, ale w naszej organizacji zdecydowaliśmy się zastosować wbudowane adnotacje danych jako standard do sprawdzania poprawności modeli w MVC. Sądzę, że moglibyśmy użyć kombinacji, ale wciąż nie ominęło tego, że nie zachowuje się tak, jak się spodziewano, to trochę pułapka. – nootn