【问题标题】:ASP.Net MVC Postback and ModelsASP.Net MVC 回发和模型
【发布时间】:2015-02-03 19:05:44
【问题描述】:

这主要是对本期评论的跟进,但我没有足够的声誉来发表评论......

ASP.Net MVC Postback a label value to your controller

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

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 的评论:

ASP.Net MVC Postback a label value to your controller

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

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

我的问题是 MVC 是否有一个好方法可以知道哪些字段被回发以便正确合并?我们只需要合并回发字段而不是空白属性。

还是只 ajaxify 整个回发而不提交表单更好?这避免了提交时的所有模型重新加载问题。

更新

为了表扬 Pablo,我接受了他的解决方案。要查看他的解决方案的简单示例,请查看 Robert Harvey 在以下答案中的评论:

ASP.Net MVC Postback and Models

【问题讨论】:

  • 这是一个很好的问题。我总是对我的模特不能永远活着感到沮丧。我似乎缺少了什么。

标签: c# asp.net-mvc model-binding


【解决方案1】:

这里的主要问题是试图将 WebForms 的 PostBack 概念融入 MVC。没有状态回发这样的事情,事情只是自动保留它们的状态。

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

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

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

我刚刚阅读了您提到的第二个问题,从它的外观来看,他的主要问题是他试图再次重用相同的 ViewModel,因此所有数据都丢失了,模型无效。解决方案确实很简单,只需将您需要的内容作为新的 ViewModel 类型发布,然后让控制器负责其余的工作。

【讨论】:

    【解决方案2】:

    [从 OP 移出]

    我认为这就是 Pablo 对那些想知道的人的建议。这似乎是解决这个问题的好模式。

    型号:

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

    【讨论】:

      【解决方案3】:

      您应该只将数据从客户端发送到服务器无法自行“计算”的服务器。如果服务器在用户第一次导航到该视图时知道标签是什么,那么如果用户无法修改它们,服务器将能够在重新加载视图时知道标签是什么。

      使用隐藏字段来识别数据库对象。所以你的SimpleClass 应该有某种Id,你将在隐藏输入中使用它。将EditorFor 用于FirstName。现在,当表单发布时,使用发送的Id 从数据库中找到正确的SimpleClass,并使用发布的值修改其FirstName 属性。 Label 属性将是 null,这没关系,因为您不需要保存它。现在,如果帖子中存在问题并且您想将相同的视图发回原样,您需要重新填充Label,就像用户第一次到达视图时所做的那样。 Id 和 FirstName 属性的值将自动与模型状态一起发送回视图。

      总结:

      • 只发布识别某事和用户什么所需的数据 可以在该视图中进行编辑。
      • 不要相信客户会向您发送任何有效的东西。用户可以将隐藏字段标签的值更改为任何值。

      【讨论】:

      • 是的,不要相信客户。客户端验证是第一步,服务器端验证是第二步。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-19
      相关资源
      最近更新 更多