【问题标题】:Updating/Returning ViewModel Back To Server更新/返回 ViewModel 回到服务器
【发布时间】:2012-10-04 16:58:16
【问题描述】:

作为 web 开发和 MVC4 的新手,我反复遇到相同的设计问题,希望有人能告诉我什么是正确/支持/等等。在 MVC4 世界中的解决方案是:

基本上,我已经使用了视图模型 koolaid,并且我的项目中的每个视图都有视图模型,其中大部分是在单页应用程序的某些内容上动态更新的部分子视图。一切顺利生成/渲染视图,然后用户在客户端更新了许多值,是时候更新服务器了。

举个例子,假设它是一个简单的容器视图模型:

public class Data {
  public List<Prop> Props { get; set; }
}

public class Prop {
  public string Id { get; set; }
  public int Value { get; set; }
}

假设用户正在向容器中添加新的道具。如何将修改后的对象返回到服务器?

到目前为止:如果服务器实时同步很重要,我可以对服务器上的每个添加/更新进行调用,然后在客户端上保持同步,或者只是让服务器返回更新后的视图。对于这样的简单场景,一切都很好。

但我经常发现自己希望客户端能够操纵对象(通过视图/js/等),并且在完成并提交之前我真的不需要在服务器上进行更新.我真正想要的是能够将对象与渲染视图一起传递,通过 Javascript 与之交互,然后在完成所有操作后将对象传递回控制器。我该怎么做? (抱歉,我花了一段时间才明白这一点!)

我见过的替代方案:

-- Quick & Dirty (Encode viewmodel properties to JavaScript in Razor):这肯定会将对象放在客户端上的 javascript 中,尽管只是将整个对象序列化到客户端 html 中而无需任何验证等似乎有点骇人听闻。 (虽然我最终确实意识到这就是对象如何使其下降的方式,但您似乎绕过了整个 MVC4 对象处理/解析。)

-- Upshot.Js 似乎曾经有过 MS 支持,但似乎已经死了:Current status of Upshot.js

-- Breeze.js (http://www.breezejs.com/) 似乎是试图接管那里,尽管我担心它是相当新的并且还没有被广泛采用。

最终让我觉得我错过了必须是一个明显的替代方案的事情是所有部分都已明确内置到 MVC4 中。例如,当您使用表单视图时,您的字段将数据绑定到控件,并且在提交表单时,会创建一个并行 JSON 对象,将其发送到控制器,然后为您解析为您的 POCO ViewModel 对象。这基本上是我正在寻找的往返(尽管保留了完整的 JSON 对象客户端)。处理这个问题的“正确”方法是什么?

【问题讨论】:

  • 你看过Knockout.js吗?它直接集成到 MVC4 中。
  • 我有。但在我看来,需要复制他们的模型是客户端的淘汰模型。还是我误会了?最终,我认为客户端框架将成为解决方案是正确的,但我还没有找到一个“利用”服务器端视图模型的框架。即使在这个简单的示例中,您仍然会创建模型客户端/应用绑定/等。对吗? (但是您可以将该模型发送回服务器,如果您将所有内容命名为相同,则返回到服务器对象的映射应该很清楚 - 所以这绝对是接近的。)
  • 实际上,我认为您是对的,我需要进一步探索一下。例如:stackoverflow.com/questions/10866285/…(@Mathletics:如果您想发表您的评论作为答案,我会接受,并将返回我找到的评论。)

标签: javascript asp.net-mvc asp.net-mvc-4 mvvm breeze


【解决方案1】:

Knockout 实际上正是我正在寻找的(或另一个客户端 MV* 框架),我只是不知道如何使用它。

感谢@Mathletics 和其他一些 SO 解决方案,为我指明了正确的方向,尤其是:How to use knockout.js with ASP.NET MVC ViewModels?

关键是真的要使用ko.mapping库,在服务端对模型进行Json编码或者序列化。特别是,这个脚本块在强类型部分视图中对我来说效果很好:

<script type="text/javascript">
function viewModel() {
    // Additional Knockout Here    
};

var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
var mvcModel = ko.mapping.fromJSON(jsonModel);

var myViewModel = new viewModel();
var g = ko.mapping.fromJS(myViewModel, mvcModel);

ko.applyBindings(g);
</script>

然后您就可以正常使用 Knockout:

<div class="row">    
    <div class="span3">
        <h3>Bound Value:</h3>
        <span data-bind="text: PropertyName"></span>
    </div>
</div>

(这需要 knockout.js、knockout.mapping.js 和 Newtonsoft.Json - 尽管 Json.Encode 也同样适用。)

然后将对象传回很容易。正常更新您的对象,当您将其传递回控制器时,您已经准备好 Json 对象,并将按正常方式解析以作为服务器端的 POCO 视图模型传回,完成这一轮旅行。

【讨论】:

    【解决方案2】:

    根据您的描述,我可以理解您需要将对象集合传递给控制器​​,然后更新集合。模型绑定到集合将使您的事情变得更容易。

    当绑定到单个字段的集合时,它变得更容易,但是当你想绑定到对象的集合时,它变得有点棘手。有顺序绑定和非顺序绑定两种选择。

    顺序绑定:

    这是将发布表单的控制器操作(HTTP POST 操作)

    public ActionResult UpdateProps(ICollection<Prop> Props) {
        return View(Props);
    }
    
    form method="post" action="/Home">    
        <input type="text" name="[0].Id" value="1001" />
        <input type="text" name="[0].Value" value="Prop1" />        
    
        <input type="text" name="[1].Id" value="" />
        <input type="text" name="[1].Value" value="NewProp" /> 
    
        <input type="submit" />
    </form>
    

    当表单发布时,值将类似于

    [0].Id=1001&[0].Value=Prop1&[1].Id=&[1].Value=NewProp

    您可以看到索引 [0] 和 [1]。模型绑定器将根据索引正确地对对象进行分组,您将获得预期的集合。发布后,您的操作将在 ICollection Props 中获得 2 个对象。一个 ID 为 1001,另一个是新添加的。

    现在您会注意到,如果您动态添加新道具,那么您需要使用脚本正确索引它。或者,如果这对您来说很难,那么您可以以上述格式发布它们,而不是索引元素。您需要解析元素并使用脚本发布表单。数据应按索引排列。解析为您提供了另一个优势,您可以只发布所需的元素,即新添加或修改的元素,而不是全部发布,从而节省有效负载。

    非顺序绑定而不是数字序列系列中,索引是唯一值,如下所示:

    [PropId1001].Id=1001&[PropId1001].Value=Prop1&[PropIdTemp233].Id=""&[PropIdTemp233].Value=NewProp

    【讨论】:

    • 感谢 Abhijit 的回复。但从某种意义上说,像这样手动布置字段,以便它们可以重新构建到我开始使用的对象中,这是我试图避免的。我更愿意在用户操作时保持客户端javascript对象的更新,然后利用那里的框架映射将它们发回。 (就像您自己创建一个对象并使用适当命名的字段以 JSON 格式发送它一样。)
    • 当您说“像那样手动布置字段”时,我没有听懂。你指的是哪些领域?带有“名称”的表单字段?
    • 道歉。我的意思是,当我将视图模型“脱水”为平面 html 字段/控件,然后“再水化”回服务器端对象时,我不想将其视为一种表单。让我再调查一些,我会更新这个问题。感谢您的回复,尽管 Abhijit。
    • 平面 HTML 视图是浏览器的最终输出,而不是 mvc 视图中的输出。在服务器端内部视图中,显然将使用 foreach 循环来解析模型生成输入字段。然后使用计数器来索引名称属性。这样当表单发布时,列表模型就会被填充。
    • 了解阿比吉特。我想我们是在互相交谈,那是我的错。让我们暂且等待另一个答案,稍后我会用更多信息更新我的问题。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多