如何在ASP.NET MVC中将视图模型转换为JSON对象?


156

我是Java开发人员,刚接触.NET。我正在一个.NET MVC2项目中,我想要一个局部视图来包装小部件。每个JavaScript小部件对象都有一个将由模型数据填充的JSON数据对象。然后,当在窗口小部件中更改数据或在另一个窗口小部件中更改数据时,用于更新此数据的方法将与事件绑定。

代码是这样的:

MyController

virtual public ActionResult DisplaySomeWidget(int id) {
  SomeModelView returnData = someDataMapper.getbyid(1);

  return View(myview, returnData);
}

myview.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeModelView>" %>

<script type="text/javascript">
  //creates base widget object;
  var thisWidgetName = new Widget();

  thisWidgetName.updateTable = function() {
    //  UpdatesData
  };
  $(document).ready(function () {
    thisWidgetName.data = <% converttoJSON(model) %>
    $(document).bind('DATA_CHANGED', thisWidgetName.updateTable());
  });
</script>

<div><%:model.name%></div>

我不知道如何发送数据SomeModelView,然后能够使用它来填充小部件以及将其转换为JSON。我已经在控制器中看到了一些简单的方法,但是在视图中却没有。我认为这是一个基本的问题,但是我已经花了几个小时试图使它变得光滑。


1
我知道这是一个老问题。但是到目前为止,还有更好的方法可以做到这一点。不要将JSON内联与您的View结果混合使用。JSON很容易通过AJAX进行序列化,可以像对待对象一样对待。JavaScript中的所有内容都应与View分开。您可以通过控制器轻松地返回模型,而无需付出任何努力。
Piotr Kula 2013年

Answers:


346

在带有剃须刀的mvc3中@Html.Raw(Json.Encode(object))似乎可以解决问题。


1
+1我使用了Html.Raw,但从未找到Json.Encode,而只是使用JavaScriptSerializer将控制器中的字符串添加到视图模型中
AaronLS

5
即使您要将生成的JSON传递给Javascript,这种方法也可以使用。如果将@ Html.Raw(...)代码作为功能参数放在<script>标记内,Razor会抱怨绿色,但是JSON确实将其传递给了被调用的JS。非常方便和光滑。+1
卡尔·海因里希·汉克

1
从MVC3开始就是这样做的方法,应该从控制器返回它。不要将json嵌入到您的Viewresult中。而是使一个控制器分别处理JSON并通过AJAX发出JSON请求。如果在视图上需要JSON,则说明您做错了什么。使用ViewModel或其他方法。
Piotr Kula

3
Json.Encode将我的2维数组编码为json中的1维数组。Newtonsoft.Json.JsonConvert.SerializeObject将两个维度正确序列化为json。因此,我建议使用后一种。
mono68 2015年

12
使用MVC 6(也许也为5)时,您需要使用Json.Serialize而不是编码。
KoalaBear

31

做得好,您才刚刚开始使用MVC,并且发现了它的第一个主要缺陷。

您真的不想在视图中将其转换为JSON,也不想在控制器中将其转换,因为这两个位置都没有意义。不幸的是,您被这种情况所困扰。

我发现要做的最好的事情是将JSON发送到ViewModel中的视图中,如下所示:

var data = somedata;
var viewModel = new ViewModel();
var serializer = new JavaScriptSerializer();
viewModel.JsonData = serializer.Serialize(data);

return View("viewname", viewModel);

然后使用

<%= Model.JsonData %>

在您看来。请注意,标准.NET JavaScriptSerializer非常糟糕。

在控制器中执行它至少使其可测试(尽管与上面的代码不完全相同-您可能希望将ISerializer视为依赖项,以便对其进行模拟)

同时更新有关您的JavaScript的方法,将以上所有包装的小部件JS这样包装是一个好习惯:

(
    // all js here
)();

这样,如果您在页面上放置了多个小部件,就不会发生冲突(除非您需要从页面的其他位置访问方法,但是在这种情况下,无论如何,您都应该在某个小部件框架中注册该小部件)。现在可能不成问题,但是最好在现在添加括号,以免日后需要时节省很多工作,这是一个很好的做法,封装功能也是一种OO做法。


1
这看起来很有趣。我本来只是将数据复制为json并将其作为viewData传递,但是这样看起来更有趣。我会玩这个,让你知道。顺便说一句,这是我第一次发布有关stackoverflow的问题,花了..5分钟的时间才能获得良好的答复,真是太好了!
克里斯·斯蒂芬斯

没有任何事情错了它,它只是不能自定义,如果你想要的任何自定义值格式化你手之前做到这一点,基本上让一切字符串:(这是日期最突出的。我知道有简便的解决方法,但他们不应该是必要!
安德鲁·布洛克

@Update我正打算使用该小部件的.net静态计数器生成唯一的对象名称。但是您写的内容看起来可以完成同样的事情,而且效果也很好。我也确实考虑将小部件“ new_widget_event”的创建绑定到页面级对象以跟踪它们,但是这样做的最初原因变成了OBE。所以我稍后可能会再次访问。感谢我将提供的所有帮助您建议但修改后的内容有所修改,以解释我为什么更喜欢它
克里斯·斯蒂芬斯,2010年

2
我撤回我以前的声明“这没有什么错”。一切都错了。
安德鲁·布洛克

为什么说我们不能从控制器返回JSON。那是应该怎么做的。使用JavaScriptSerializerReturn Json(object)两者都使用相同的序列化器。只要您定义正确的模型,还将相同的JSON发送回控制器将为您重建对象。也许在MVC2期间它是一个主要缺点。.但是今天它轻而易举,非常方便。您应该更新您的答案以反映这一点。
Piotr Kula

18

我发现这样做很不错(在视图中使用):

    @Html.HiddenJsonFor(m => m.TrackingTypes)

这是相应的辅助方法Extension类:

public static class DataHelpers
{
    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        return HiddenJsonFor(htmlHelper, expression, (IDictionary<string, object>) null);
    }

    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        return HiddenJsonFor(htmlHelper, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        var tagBuilder = new TagBuilder("input");
        tagBuilder.MergeAttributes(htmlAttributes);
        tagBuilder.MergeAttribute("name", name);
        tagBuilder.MergeAttribute("type", "hidden");

        var json = JsonConvert.SerializeObject(metadata.Model);

        tagBuilder.MergeAttribute("value", json);

        return MvcHtmlString.Create(tagBuilder.ToString());
    }
}

它不是超级复杂的,但是它解决了将其放置在哪里的问题(在Controller还是视图中?)答案显然是:都不;)


在我看来,这很不错而且很干净,并且包装在一个可重用的帮助程序中。干杯,J
约翰·

6

您可以使用 Json直接从操作中,

您的操作将如下所示:

virtual public JsonResult DisplaySomeWidget(int id)
{
    SomeModelView returnData = someDataMapper.getbyid(id);
    return Json(returnData);
}

编辑

刚刚看到您认为这是ModelView的,因此上述内容并非严格正确,您必须Ajax调用controller方法来获取此信息,ascx然后再没有模型本身,我将保留我的代码以防万一对您有用,您可以修改通话

编辑2 只需将id放入代码中


1
但是他无法将其渲染到视图中,因此他必须进行第二次ajax调用
Andrew Bullock 2010年

谢谢,我本来是使用jQuery get json调用进行此操作的,并计划让HTML元素从json中自行填充。但是,我们现在遵循的模式是我们的视图应该返回modelView,这是填充基本HTML元素(例如表格等)的最简单方法。我可以以JSON格式发送与ViewData相同的数据,但这似乎很浪费。
克里斯·斯蒂芬斯

2
您不应在JSON中嵌入View Result。OP要么需要遵循实践的标准MVC并返回模型或视图模型,要么执行AJAX。在视图中嵌入JSON绝对没有理由。那只是很脏的代码。该答案是正确的方法,也是Microsoft实践推荐的方法。否决票是不必要的,这绝对是正确的答案。我们不应该鼓励不良的编码习惯。通过AJAX的JSON或通过视图的模型。没有人喜欢带有混合标记的意大利面条代码!
Piotr Kula

此解决方案将导致以下问题:stackoverflow.com/questions/10543953/…–
珍妮·奥利莉



0

扩展了Dave的回答。您可以创建一个简单的HtmlHelper

public static IHtmlString RenderAsJson(this HtmlHelper helper, object model)
{
    return helper.Raw(Json.Encode(model));
}

在您看来:

@Html.RenderAsJson(Model)

这样,如果您出于某种原因想要稍后更改逻辑,则可以集中创建JSON的逻辑。


0

安德鲁的反应很好,但我想稍微周一点。不同之处在于我希望ModelViews中没有开销数据。只是对象的数据。ViewData似乎适合开销数据,但我当然是新手。我建议做这样的事情。

控制者

virtual public ActionResult DisplaySomeWidget(int id)
{
    SomeModelView returnData = someDataMapper.getbyid(1);
    var serializer = new JavaScriptSerializer();
    ViewData["JSON"] = serializer.Serialize(returnData);
    return View(myview, returnData);
}

视图

//create base js object;
var myWidget= new Widget(); //Widget is a class with a public member variable called data.
myWidget.data= <%= ViewData["JSON"] %>;

这对您的作用是,它在JSON中为您提供了与ModelView中相同的数据,因此您可以将JSON返回给控制器,并且它具有所有部分。这类似于仅通过JSONRequest进行请求,但是它需要少调用一次,因此可以节省您的开销。顺便说一句,这对于Dates很时髦,但这似乎又是另一个话题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.