2

作为 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 支持,但似乎已经死了:Upshot.js 的当前状态

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

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

4

2 回答 2

2

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

感谢@Mathletics 和其他一些 SO 解决方案为我指明了正确的方向,尤其是:如何将 knockout.js 与 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 视图模型传回,完成这一轮旅行。

于 2012-10-14T23:09:08.803 回答
0

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

当绑定到单个字段的集合时,它变得更容易,但是当你想绑定到对象的集合时,它变得有点棘手。有 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

于 2012-10-14T15:45:47.403 回答