ASP.Net MVC回发和模型

Rob*_*Rob 10 c# asp.net-mvc model-binding

这主要是对本期评论的后续评论,但我没有足够的声誉评论......

ASP.Net MVC将标签值回发给控制器

假设我有一个简单的模型:

public class SimpleClass
{
    public String Label { get; set; }
    public String FirstName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

标签是基于用户/客户端更改的,因此它不能是DataAttribute.如果发布回发处理问题时,我们需要重绘整个页面.这是前一篇文章的关键问题.接受的解决方案是这样做:

@Html.DisplayTextFor(model => model.Label)
@Html.HiddenFor(model => model.Label)
@Html.EditorFor(model => model.FirstName)
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为它有效.但是我们的模型更加复杂和广泛.这种方法会导致大量的隐藏字段,这似乎是一个非常肮脏的解决方案.

这让我想到JP的评论:

ASP.Net MVC将标签值回发给控制器

解决方案是重新加载模型.但它不仅仅是重新加载,它也是一种合并,因为您希望保留任何客户端数据更改.

default: SimpleClass { Label="TheLabel", FirstName="Rob"}
postedback: SimpleClass { Label="", FirstName="Steve" }
we want: SimpleClass { Label="TheLabel", "FirstName="Steve" }
Run Code Online (Sandbox Code Playgroud)

我的问题是MVC有一个很好的方法来知道哪些字段被回发,所以它正确合并?我们只需要合并回传字段而不是空白属性.

或者只是更好地整理回发而不是表单提交?这样可以避免提交时出现所有模型重新加载问题.

更新

为了给予Pablo信用,我接受了他的解决方案.要查看我的解决方案的简单示例,请在下面的答案中查看Robert Harvey的评论:

ASP.Net MVC回发和模型

Pab*_*meo 6

这里的主要问题是尝试将WebForms的PostBack概念融入MVC.没有状态回发之类的东西只会自动保留其状态.

您只有绑定到视图的ViewModel,以及由视图发布到Controller的ViewModel.它们甚至不一定需要是同一类型.这意味着,控制器应该只接收用户确实可以更改的数据,而不是具有许多属性的大对象,这些属性是初始ViewModel的一部分,但是只读.

标签通常表示只读文本,它们不是可编辑的表单元素.这就是为什么你必须使用隐藏字段的原因.

是的,有时这意味着您必须在控制器中重新加载原始数据,并与您发布的新数据同步,这不一定是件坏事.如果将只读数据绑定到用户无法手动编辑的视图,则您不应该真正信任之后在帖子中返回的数据.仅仅因为你的html可能试图让它成为只读并不意味着我不能操纵帖子并最终在你不知道的情况下改变你的"只读"数据.

我刚看了你提到的第二个问题,从它的外观来看,他的主要问题是他试图再次重复使用相同的ViewModel,因此所有数据都丢失了,模型无效.解决方案确实很简单,只发布你需要的东西,作为一个新的ViewModel类型,并让控制器处理其余的事情.


Rob*_*vey 5

[移至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; }
    }
Run Code Online (Sandbox Code Playgroud)

控制器动作:

    [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);
    }
Run Code Online (Sandbox Code Playgroud)

视图:

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

}
Run Code Online (Sandbox Code Playgroud)