The ability to let the model handle its own validation has lead me to begin playing with the MVC 2 preview release. So far, I like the simplicity of the validation scheme. However, I have run into a roadblock. This validation style works fine for simple view model objects. For example if I have a model object named car and I'm looking to create a view to create a new car:
让模型自己处理验证的能力使我开始使用MVC 2预览版。到目前为止,我喜欢验证方案的简单性。然而,我遇到了障碍。这种验证风格适用于简单的视图模型对象。例如,如果我有一个名为car的模型对象,我想创建一个视图来创建一个新汽车:
-----Model-------
- - - - -模型- - - - - - -
public class Car
{
public string Id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
}
-----Controller---------
- - - - - - - - - - - -控制器
public class CarController : Controller
{
public ActionResult Create()
{
Car myCar = new Car();
return View("Create", myCar);
}
[HttpPost]
public ActionResult Create(Car myCar)
{
if (!ModelState.IsValid)
{
return View("Create", myCar);
}
//Do something on success
return View("Index");
}
}
-------View--------------
- - - - - -查看- - - - - - - - - - - - - - -
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Car>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<%
using (Html.BeginForm()) {%>
<fieldset>
<legend>Edit User Profile</legend>
<p>
<label for="Id">Id:</label>
<%= Html.TextBox("Id", Model.Id)%>
<%= Html.ValidationMessage("Id") %>
</p>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name", Model.Name)%>
<%= Html.ValidationMessage("Name") %>
</p>
<p>
<label for="Color">Color:</label>
<%= Html.TextBox("Color", Model.Color)%>
<%= Html.ValidationMessage("Color") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
</asp:Content>
This works like a charm. But not all of my views, or model objects for that matter, are simple. I might have a car model object like:
这就像一种魅力。但并不是我的所有视图或模型对象都很简单。我可能有一个汽车模型对象,比如:
-----Model-------
- - - - -模型- - - - - - -
public class PaintScheme
{
public int Red { get; set; }
public int Blue { get; set; }
public int Green { get; set; }
}
public class Car
{
public string Id { get; set; }
public string Name { get; set; }
public PaintScheme Paint{ get; set; }
}
-------View--------------
- - - - - -查看- - - - - - - - - - - - - - -
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Car>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<%
using (Html.BeginForm()) {%>
<fieldset>
<legend>Edit User Profile</legend>
<p>
<label for="Id">Id:</label>
<%= Html.TextBox("Id", Model.Id)%>
<%= Html.ValidationMessage("Id") %>
</p>
<p>
<label for="Name">Name:</label>
<%= Html.TextBox("Name", Model.Name)%>
<%= Html.ValidationMessage("Name") %>
</p>
<p>
<label for="Red">Color Red:</label>
<%= Html.TextBox("Red", Model.Paint.Red)%>
<%= Html.ValidationMessage("Red") %>
</p>
<p>
<label for="Blue">Color Blue:</label>
<%= Html.TextBox("Blue", Model.Paint.Blue)%>
<%= Html.ValidationMessage("Blue") %>
</p>
<p>
<label for="Green">Color Green:</label>
<%= Html.TextBox("Green", Model.Paint.Green)%>
<%= Html.ValidationMessage("Green") %>
</p>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
</asp:Content>
When I add the PaintScheme properties to my view, they are not carried over with the "myCar" object passed into my controller action. Is there a way to resolve this without having to rebuild the object from a form collection and then checking the ModelState?
当我将PaintScheme属性添加到视图中时,它们不会与传递到控制器动作中的“myCar”对象一起传递。是否有一种方法可以解决这个问题,而不必从表单集合中重新构建对象,然后检查ModelState?
3 个解决方案
#1
1
- You should have the public setter for properties you want to be bound. I wonder how the first sample works for you as everything is private.
- 您应该拥有要绑定的属性的公共setter。我想知道第一个示例是如何工作的,因为一切都是私有的。
- You have to post at least one value of PaintScheme property to be able to bind it.
- 您必须发布至少一个值的PaintScheme属性才能绑定它。
- All child properties should be prefixed with the path to it. Where path can be defined as *(PropertyName.)**.
- 所有子属性都应该以指向它的路径为前缀。其中路径可以定义为*(PropertyName.)**。
It seems the point 3 is not satisfied in the View. Change the appropriate part of the view to this:
看来第三点在观点上并不令人满意。将视图的适当部分改为:
<p>
<label for="Red">Color Red:</label>
<%= Html.TextBox("Paint.Red")%>
<%= Html.ValidationMessage("Red") %>
</p>
<p>
<label for="Blue">Color Blue:</label>
<%= Html.TextBox("Paint.Blue")%>
<%= Html.ValidationMessage("Blue") %>
</p>
<p>
<label for="Green">Color Green:</label>
<%= Html.TextBox("Paint.Green")%>
<%= Html.ValidationMessage("Green") %>
</p>
Additionally note that I removed explicit values from the TextBox helper to avoid possible NullReferenceException.
另外请注意,我从文本框helper中删除了显式值,以避免可能的NullReferenceException。
#2
1
The easiest way to deal with this is to flatten your model using a dto. Then use automapper to map your domain object to your view model. This translation could be defined in such a way that you convert the enum to a string and back. Then validation will work and your bom won't touch the view maintaining your seperation of concerns fairly well.
处理此问题的最简单方法是使用dto使模型变平。然后使用automapper将域对象映射到视图模型。可以用这样的方式定义这个转换,将enum转换为字符串并返回。然后验证将起作用,而您的bom将不会触及保持您的关注点隔离的视图。
#3
0
For the color part you can have something like this, being an int I dont think you will use a textbox but this will bind your red color (if the input value is a number)
对于颜色部分,你可以有这样的东西,作为一个int类型我不认为你会使用一个文本框但是这会绑定你的红色(如果输入值是一个数字)
<p>
<label for="Red">Color:</label>
<%= Html.TextBox("Red", Model.Paint.Red)%>
<%= Html.ValidationMessage("Red") %>
</p>
#1
1
- You should have the public setter for properties you want to be bound. I wonder how the first sample works for you as everything is private.
- 您应该拥有要绑定的属性的公共setter。我想知道第一个示例是如何工作的,因为一切都是私有的。
- You have to post at least one value of PaintScheme property to be able to bind it.
- 您必须发布至少一个值的PaintScheme属性才能绑定它。
- All child properties should be prefixed with the path to it. Where path can be defined as *(PropertyName.)**.
- 所有子属性都应该以指向它的路径为前缀。其中路径可以定义为*(PropertyName.)**。
It seems the point 3 is not satisfied in the View. Change the appropriate part of the view to this:
看来第三点在观点上并不令人满意。将视图的适当部分改为:
<p>
<label for="Red">Color Red:</label>
<%= Html.TextBox("Paint.Red")%>
<%= Html.ValidationMessage("Red") %>
</p>
<p>
<label for="Blue">Color Blue:</label>
<%= Html.TextBox("Paint.Blue")%>
<%= Html.ValidationMessage("Blue") %>
</p>
<p>
<label for="Green">Color Green:</label>
<%= Html.TextBox("Paint.Green")%>
<%= Html.ValidationMessage("Green") %>
</p>
Additionally note that I removed explicit values from the TextBox helper to avoid possible NullReferenceException.
另外请注意,我从文本框helper中删除了显式值,以避免可能的NullReferenceException。
#2
1
The easiest way to deal with this is to flatten your model using a dto. Then use automapper to map your domain object to your view model. This translation could be defined in such a way that you convert the enum to a string and back. Then validation will work and your bom won't touch the view maintaining your seperation of concerns fairly well.
处理此问题的最简单方法是使用dto使模型变平。然后使用automapper将域对象映射到视图模型。可以用这样的方式定义这个转换,将enum转换为字符串并返回。然后验证将起作用,而您的bom将不会触及保持您的关注点隔离的视图。
#3
0
For the color part you can have something like this, being an int I dont think you will use a textbox but this will bind your red color (if the input value is a number)
对于颜色部分,你可以有这样的东西,作为一个int类型我不认为你会使用一个文本框但是这会绑定你的红色(如果输入值是一个数字)
<p>
<label for="Red">Color:</label>
<%= Html.TextBox("Red", Model.Paint.Red)%>
<%= Html.ValidationMessage("Red") %>
</p>