[英]ASP.Net MVC Postback and Models
这主要是对本期评论的后续评论,但我没有足够的声誉评论......
假设我有一个简单的模型:
public class SimpleClass
{
public String Label { get; set; }
public String FirstName { get; set; }
}
标签是基于用户/客户端更改的,因此它不能是DataAttribute。 如果发布回发处理问题时,我们需要重绘整个页面。 这是前一篇文章的关键问题。 接受的解决方案是这样做:
@Html.DisplayTextFor(model => model.Label)
@Html.HiddenFor(model => model.Label)
@Html.EditorFor(model => model.FirstName)
这是有道理的,因为它有效。 但是我们的模型更加复杂和广泛。 这种方法会导致大量的隐藏字段,这似乎是一个非常肮脏的解决方案。
这让我想到JP的评论:
解决方案是重新加载模型。 但它不仅仅是重新加载,它也是一种合并,因为您希望保留任何客户端数据更改。
default: SimpleClass { Label="TheLabel", FirstName="Rob"}
postedback: SimpleClass { Label="", FirstName="Steve" }
we want: SimpleClass { Label="TheLabel", "FirstName="Steve" }
我的问题是MVC有一个很好的方法来知道哪些字段被回发,所以它正确合并? 我们只需要合并回传字段而不是空白属性。
或者只是更好地整理回发而不是表单提交? 这样可以避免提交时出现所有模型重新加载问题。
为了给予Pablo信用,我接受了他的解决方案。 要查看我的解决方案的简单示例,请在下面的答案中查看Robert Harvey的评论:
这里的主要问题是尝试将WebForms的PostBack概念融入MVC。 没有状态回发之类的东西只会自动保留其状态。
您只有绑定到视图的ViewModel,以及由视图发布到Controller的ViewModel。 它们甚至不一定需要是同一类型。 这意味着,控制器应该只接收用户确实可以更改的数据,而不是具有许多属性的大对象,这些属性是初始ViewModel的一部分,但是只读。
标签通常表示只读文本,它们不是可编辑的表单元素。 这就是为什么你必须使用隐藏字段的原因。
是的,有时这意味着您必须重新加载控制器中的原始数据,并与您发布的新数据同步,这不一定是坏事。 如果将只读数据绑定到用户无法手动编辑的视图,则您不应该真正信任之后在帖子中返回的数据。 仅仅因为你的html可能试图让它成为只读并不意味着我不能操纵帖子并最终在你不知道的情况下改变你的“只读”数据。
我刚看了你提到的第二个问题,从它的外观来看,他的主要问题是他试图再次重复使用相同的ViewModel,因此所有数据都丢失了,模型无效。 解决方案确实很简单,只发布你需要的东西,作为一个新的ViewModel类型,并让控制器处理其余的事情。
[移至OP]
我认为这就是巴勃罗对那些想知道的人的建议。 这似乎是解决这个问题的好方法。
楷模:
public class SimpleClass : SimpleClassPostBack
{
public String Label { get; set; }
public SimpleClass()
{
// simulate default loading
Label = "My Label";
FirstName = "Rob";
}
}
// contains only editable by the user fields
public class SimpleClassPostBack
{
public String FirstName { get; set; }
}
控制器动作:
[HttpGet]
public ActionResult SimpleClassExample3()
{
SimpleClass simpleClass = new SimpleClass();
return View(simpleClass);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SimpleClassExample3(SimpleClassPostBack postBackSimpleClass)
{
Boolean errorOccurred = true;
if (!errorOccurred)
{
// do whatever success action is necessary
}
// redraw the page, an error occurred
// reload the original model
SimpleClass simpleClass = new SimpleClass();
// move the posted back data into the model
// can use fancy reflection to automate this
simpleClass.FirstName = postBackSimpleClass.FirstName;
// bind the view
return View(simpleClass);
}
视图:
@model SimpleClass
@{
ViewBag.Title = "Simple Class Example3";
}
<h2>Simple Class Example3</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<label for="FirstName">@Html.DisplayFor(m => m.Label)</label>
@Html.EditorFor(m => m.FirstName)
<br/>
<button>Submit</button>
}
您应该只将数据从客户端发送到服务器无法自行“弄清楚”的服务器。 如果服务器在用户首次导航到该视图时知道标签是什么,那么如果用户无法修改它们,则服务器将能够在重新加载视图时知道标签是什么。
使用隐藏字段标识数据库对象。 所以你的SimpleClass
应该有一些你将在隐藏输入中使用的Id
。 使用EditorFor
for FirstName
。 现在,当发布表单时,使用发送的Id
从数据库中查找正确的SimpleClass
,并使用发布的值修改其FirstName
属性。 Label
属性为null
,因为您不需要保存它。 现在,如果帖子中存在问题,并且您希望像往常一样发回相同的视图,则需要以与用户第一次到达视图时相同的方式重新填充Label
。 Id
和FirstName
属性的值将自动发送回具有模型状态的视图。
综上所述:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.