简体   繁体   English

ASP.Net MVC回发和模型

[英]ASP.Net MVC Postback and Models

This is mostly a follow-up to a comment in this issu, but I don't have enough reputation to comment ... 这主要是对本期评论的后续评论,但我没有足够的声誉评论......

ASP.Net MVC Postback a label value to your controller ASP.Net MVC将标签值回发给控制器

Let's say I have a simple model: 假设我有一个简单的模型:

public class SimpleClass
{
    public String Label { get; set; }
    public String FirstName { get; set; }
}

Label is changed based on user/client so it can't be a DataAttribute. 标签是基于用户/客户端更改的,因此它不能是DataAttribute。 If when posted back processing problems occur, we need to redraw the entire page. 如果发布回发处理问题时,我们需要重绘整个页面。 This is the crux of the problem of the previous post. 这是前一篇文章的关键问题。 The accepted solution is to do this: 接受的解决方案是这样做:

@Html.DisplayTextFor(model => model.Label)
@Html.HiddenFor(model => model.Label)
@Html.EditorFor(model => model.FirstName)

That makes sense in that it works. 这是有道理的,因为它有效。 But our models are much more complicated and extensive. 但是我们的模型更加复杂和广泛。 This method will result in a ton of hidden fields which seems like a very dirty solution. 这种方法会导致大量的隐藏字段,这似乎是一个非常肮脏的解决方案。

This brings me to JP's comment: 这让我想到JP的评论:

ASP.Net MVC Postback a label value to your controller ASP.Net MVC将标签值回发给控制器

The solution there is to reload the model. 解决方案是重新加载模型。 But it's not just a reload, it's also a merge since you want to preserve any client-side data changes. 但它不仅仅是重新加载,它也是一种合并,因为您希望保留任何客户端数据更改。

default: SimpleClass { Label="TheLabel", FirstName="Rob"}
postedback: SimpleClass { Label="", FirstName="Steve" }
we want: SimpleClass { Label="TheLabel", "FirstName="Steve" }

My question is does MVC have a good way to know what fields were postedback so it merges correctly? 我的问题是MVC有一个很好的方法来知道哪些字段被回发,所以它正确合并? We would need to only merge postedback fields not blank properties. 我们只需要合并回传字段而不是空白属性。

Or is it better to just ajaxify the entire postback and not do a form submit? 或者只是更好地整理回发而不是表单提交? This avoids all model reload issues on submit. 这样可以避免提交时出现所有模型重新加载问题。

Update 更新

To give Pablo credit I accepted his solution. 为了给予Pablo信用,我接受了他的解决方案。 To see my simple example of his solution, check Robert Harvey's comment in the Answers below: 要查看我的解决方案的简单示例,请在下面的答案中查看Robert Harvey的评论:

ASP.Net MVC Postback and Models ASP.Net MVC回发和模型

The main problem here is in trying to fit WebForms' PostBack concepts into MVC. 这里的主要问题是尝试将WebForms的PostBack概念融入MVC。 There is no such thing as a stateful postback where things just automatically retain their state. 没有状态回发之类的东西只会自动保留其状态。

You only have ViewModels that are bound to the view, and ViewModels that are posted by the view to the Controller. 您只有绑定到视图的ViewModel,以及由视图发布到Controller的ViewModel。 They don't even necessarily need to be of the same Type. 它们甚至不一定需要是同一类型。 Meaning, the controller should only receive the data that the user indeed can change, not large objects with many properties that were part of the initial ViewModel but are read-only. 这意味着,控制器应该只接收用户确实可以更改的数据,而不是具有许多属性的大对象,这些属性是初始ViewModel的一部分,但是只读。

Labels commonly represent read-only texts and they are not editable form elements. 标签通常表示只读文本,它们不是可编辑的表单元素。 Which is why you have to use hidden fields for that. 这就是为什么你必须使用隐藏字段的原因。

And yes, sometimes that implies that you have to reload the original data in the controller, and sync up with new data that you posted, which isn't necessarily a bad thing. 是的,有时这意味着您必须重新加载控制器中的原始数据,并与您发布的新数据同步,这不一定是坏事。 If you bind read-only data to a view, which the user can't manually edit, you shouldn't really trust that data coming back in a post afterwards. 如果将只读数据绑定到用户无法手动编辑的视图,则您不应该真正信任之后在帖子中返回的数据。 Just because your html might try to make it read-only doesn't mean I can't manipulate the post and ultimately change your "read-only" data without you knowing. 仅仅因为你的html可能试图让它成为只读并不意味着我不能操纵帖子并最终在你不知道的情况下改变你的“只读”数据。

I just read the second question you mentioned, and from the looks of it, his main problem was that he was trying to reuse the same ViewModel again, so all the data was missing and the model wasn't valid. 我刚看了你提到的第二个问题,从它的外观来看,他的主要问题是他试图再次重复使用相同的ViewModel,因此所有数据都丢失了,模型无效。 The solution to that is indeed quite simple, ONLY post what you need, as a new ViewModel type, and have the controller take care of the rest. 解决方案确实很简单,只发布你需要的东西,作为一个新的ViewModel类型,并让控制器处理其余的事情。

[Moved from OP] [移至OP]

I think this is what Pablo is suggesting for those who are wondering. 我认为这就是巴勃罗对那些想知道的人的建议。 It seems to be a good pattern to resolve this problem. 这似乎是解决这个问题的好方法。

Models: 楷模:

    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; }
    }

Controller Actions: 控制器动作:

    [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);
    }

View: 视图:

@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>

}

You should only send data from the client to the server that the server can't "figure out" on its own. 您应该只将数据从客户端发送到服务器无法自行“弄清楚”的服务器。 If the server knows what the labels were when the user first navigated to that view then if the user cannot modify them, the server will be able to know what the labels are when reloading the view. 如果服务器在用户首次导航到该视图时知道标签是什么,那么如果用户无法修改它们,则服务器将能够在重新加载视图时知道标签是什么。

Use hidden fields to identify the database objects. 使用隐藏字段标识数据库对象。 So your SimpleClass should probably have some sort of Id which you will use in the hidden input. 所以你的SimpleClass应该有一些你将在隐藏输入中使用的Id Use the EditorFor for FirstName . 使用EditorFor for FirstName Now when the form is posted, use the sent Id to find the correct SimpleClass from the database and modify its FirstName property with the value posted. 现在,当发布表单时,使用发送的Id从数据库中查找正确的SimpleClass ,并使用发布的值修改其FirstName属性。 The Label property will be null which is ok since you don't need to save it. Label属性为null ,因为您不需要保存它。 Now if there's a problem in the post and you want to send the same view back like it was, you need to repopulate the Label the same way you did when the user arrived to the view for the first time. 现在,如果帖子中存在问题,并且您希望像往常一样发回相同的视图,则需要以与用户第一次到达视图时相同的方式重新填充Label The values of Id and FirstName properties will be automatically sent back to the view with the model state. IdFirstName属性的值将自动发送回具有模型状态的视图。

In summary: 综上所述:

  • Only post data that is needed to identify something and what the user can edit in that view. 仅发布识别内容所需的数据以及用户可在该视图中编辑的内容。
  • Don't trust the client to send you anything valid. 不要相信客户向您发送任何有效的信息。 The user can change the values of the hidden field labels to anything. 用户可以将隐藏字段标签的值更改为任何值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM