ASP。NET MVC:如何将视图模型转换成Json对象

时间:2022-11-30 18:01:08

I am Java developer new to .NET. I am working on a .Net MVC2 project where I want to have a partial view to wrap a widget. Each JS widget object has a JSON data object that would be populated by the model data. Then methods to update this data bound to events when data is changed in the widget or if that data is changed in another widget. The code is something like this.

我是。net的Java开发人员。我正在开发一个。net MVC2项目,我希望有一个部分视图来包装一个小部件。每个JS小部件对象都有一个由模型数据填充的JSON数据对象。然后,方法更新绑定到事件的数据,当小部件中的数据发生更改或该数据在另一个小部件中发生更改时。代码是这样的。

MyController

MyController

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

    return View(myview, returnData);
}

myview.ascx

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>

What I don't know is how to send the data over as SomeModelView and then be able to use that to populate the widget as well as convert that to Json. I had seem some real simple ways to do it in the controller but not in the view. I figure this is a basic question bu I've been going for a few hours trying to make this slick.

我不知道的是如何将数据作为SomeModelView发送过来,然后使用它填充小部件,并将其转换为Json。我似乎有一些简单的方法可以在控制器中实现,但在视图中不行。我认为这是一个基本的问题,但我已经花了几个小时试图把它弄得更圆滑。

8 个解决方案

#1


307  

In mvc3 with razor @Html.Raw(Json.Encode(object)) seems to do the trick.

在mvc3中,razor @Html.Raw(Json.Encode(对象))似乎就是这样。

#2


28  

Well done, you've only just started using MVC and you've found its first major flaw.

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

You don't really want to be converting it to JSON in the view, and you don't really want to convert it in the controller, as neither of these locations make sense. Unfortunately, you're stuck with this situation.

你不想在视图中把它转换成JSON,也不想在控制器中转换它,因为这两个位置都没有意义。不幸的是,你陷入了这种情况。

The best thing I've found to do is send the JSON to the view in a ViewModel, like this:

我找到的最好的方法是将JSON发送到ViewModel中的视图,如下所示:

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

return View("viewname", viewModel);

then use

然后使用

<%= Model.JsonData %>

in your view. Be aware that the standard .NET JavaScriptSerializer is pretty crap.

在你的观点。注意,标准的。net JavaScriptSerializer是相当糟糕的。

doing it in the controller at least makes it testable (although not exactly like the above - you probably want to take an ISerializer as a dependency so you can mock it)

在控制器中这样做至少可以使它可测试(尽管不完全像上面那样—您可能希望使用一个ISerializer作为依赖项,以便您可以模拟它)

Update also, regarding your JavaScript, it would be good practice to wrap ALL the widget JS you have above like so:

更新,关于你的JavaScript,最好将上面所有的小部件JS封装起来:

(
    // all js here
)();

this way if you put multiple widgets on a page, you won't get conflicts (unless you need to access the methods from elsewhere in the page, but in that case you should be registering the widget with some widget framework anyway). It may not be a problem now, but it would be good practice to add the brackets now to save yourself muchos effort in the future when it becomes a requirement, it's also good OO practice to encapsulate the functionality.

这样,如果在页面上放置多个小部件,就不会产生冲突(除非您需要从页面的其他地方访问方法,但是在这种情况下,您应该使用一些小部件框架注册小部件)。现在这可能不是一个问题,但是现在添加括号将是一个很好的实践,以便在将来成为需求时节省您的muchos工作,封装功能也是很好的OO实践。

#3


18  

I found it to be pretty nice to do it like this (usage in the view):

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

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

Here is the according helper method Extension class:

下面是根据辅助方法扩展类:

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());
    }
}

It is not super-sofisticated, but it solves the problem of where to put it (in Controller or in view?) The answer is obviously: neither ;)

它不是超级固定的,但是它解决了把它放在哪里的问题(在控制器中还是在视图中?)答案很明显:两者都不是;

#4


4  

You can use Json from the action directly,

可以直接从动作中使用Json,

Your action would be something like this:

你的行动应该是这样的:

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

Edit

编辑

Just saw that you assume this is the Model of a View so the above isn't strictly correct, you would have to make an Ajax call to the controller method to get this, the ascx would not then have a model per se, I will leave my code in just in case it is useful to you and you can amend the call

刚刚看到,你认为这是一个视图的模型上面不是严格地正确,你将不得不做出一个Ajax调用控制器方法得到这个,然后ascx不会本身有一个模型,我将离开我的代码在以防对你有用,你可以修改调用

#5


3  

@Html.Raw(Json.Encode(object)) can be used to convert the View Modal Object to JSON

可以使用@Html.Raw(Json.Encode(对象))将视图模态对象转换为JSON

#6


0  

<htmltag id=’elementId’ data-ZZZZ’=’@Html.Raw(Json.Encode(Model))’ />

Refer https://highspeedlowdrag.wordpress.com/2014/08/23/mvc-data-to-jquery-data/

请参阅https://highspeedlowdrag.wordpress.com/2014/08/23/mvc-data-to-jquery-data/

I did below and it works like charm.

我在下面做了,它就像魅力一样。

<input id="hdnElement" class="hdnElement" type="hidden" value='@Html.Raw(Json.Encode(Model))'>

<输入id="hdnelement" class="hdnElement" type="hidden" value="@Html.Raw(Json.Encode(Model)))">

#7


0  

Extending the great answer from Dave. You can create a simple HtmlHelper.

戴夫回答得很好。您可以创建一个简单的HtmlHelper。

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

And in your view:

在你的观点:

@Html.RenderAsJson(Model)

This way you can centralize the logic for creating the JSON if you, for some reason, would like to change the logic later.

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

#8


0  

Andrew had a great response but I wanted to tweek it a little. The way this is different is that I like my ModelViews to not have overhead data in them. Just the data for the object. It seem that ViewData fits the bill for over head data, but of course I'm new at this. I suggest doing something like this.

安德鲁得到了很好的回应,但我想再多说一点。不同的是,我希望我的模型视图中不包含开销数据。只是对象的数据。看起来,ViewData正好符合了head数据的要求,但是我当然是新手了。我建议做这样的事。

Controller

控制器

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

View

视图

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

What This does for you is it gives you the same data in your JSON as in your ModelView so you can potentially return the JSON back to your controller and it would have all the parts. This is similar to just requesting it via a JSONRequest however it requires one less call so it saves you that overhead. BTW this is funky for Dates but that seems like another thread.

它为你做的是它在你的JSON中给你和在你的ModelView中一样的数据所以你可以把JSON返回给你的控制器它会有所有的部分。这类似于通过JSONRequest请求它,但是它需要一个更少的调用,因此它可以节省开销。顺便说一句,这对于约会来说很时髦,但这似乎是另一种思路。

#1


307  

In mvc3 with razor @Html.Raw(Json.Encode(object)) seems to do the trick.

在mvc3中,razor @Html.Raw(Json.Encode(对象))似乎就是这样。

#2


28  

Well done, you've only just started using MVC and you've found its first major flaw.

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

You don't really want to be converting it to JSON in the view, and you don't really want to convert it in the controller, as neither of these locations make sense. Unfortunately, you're stuck with this situation.

你不想在视图中把它转换成JSON,也不想在控制器中转换它,因为这两个位置都没有意义。不幸的是,你陷入了这种情况。

The best thing I've found to do is send the JSON to the view in a ViewModel, like this:

我找到的最好的方法是将JSON发送到ViewModel中的视图,如下所示:

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

return View("viewname", viewModel);

then use

然后使用

<%= Model.JsonData %>

in your view. Be aware that the standard .NET JavaScriptSerializer is pretty crap.

在你的观点。注意,标准的。net JavaScriptSerializer是相当糟糕的。

doing it in the controller at least makes it testable (although not exactly like the above - you probably want to take an ISerializer as a dependency so you can mock it)

在控制器中这样做至少可以使它可测试(尽管不完全像上面那样—您可能希望使用一个ISerializer作为依赖项,以便您可以模拟它)

Update also, regarding your JavaScript, it would be good practice to wrap ALL the widget JS you have above like so:

更新,关于你的JavaScript,最好将上面所有的小部件JS封装起来:

(
    // all js here
)();

this way if you put multiple widgets on a page, you won't get conflicts (unless you need to access the methods from elsewhere in the page, but in that case you should be registering the widget with some widget framework anyway). It may not be a problem now, but it would be good practice to add the brackets now to save yourself muchos effort in the future when it becomes a requirement, it's also good OO practice to encapsulate the functionality.

这样,如果在页面上放置多个小部件,就不会产生冲突(除非您需要从页面的其他地方访问方法,但是在这种情况下,您应该使用一些小部件框架注册小部件)。现在这可能不是一个问题,但是现在添加括号将是一个很好的实践,以便在将来成为需求时节省您的muchos工作,封装功能也是很好的OO实践。

#3


18  

I found it to be pretty nice to do it like this (usage in the view):

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

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

Here is the according helper method Extension class:

下面是根据辅助方法扩展类:

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());
    }
}

It is not super-sofisticated, but it solves the problem of where to put it (in Controller or in view?) The answer is obviously: neither ;)

它不是超级固定的,但是它解决了把它放在哪里的问题(在控制器中还是在视图中?)答案很明显:两者都不是;

#4


4  

You can use Json from the action directly,

可以直接从动作中使用Json,

Your action would be something like this:

你的行动应该是这样的:

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

Edit

编辑

Just saw that you assume this is the Model of a View so the above isn't strictly correct, you would have to make an Ajax call to the controller method to get this, the ascx would not then have a model per se, I will leave my code in just in case it is useful to you and you can amend the call

刚刚看到,你认为这是一个视图的模型上面不是严格地正确,你将不得不做出一个Ajax调用控制器方法得到这个,然后ascx不会本身有一个模型,我将离开我的代码在以防对你有用,你可以修改调用

#5


3  

@Html.Raw(Json.Encode(object)) can be used to convert the View Modal Object to JSON

可以使用@Html.Raw(Json.Encode(对象))将视图模态对象转换为JSON

#6


0  

<htmltag id=’elementId’ data-ZZZZ’=’@Html.Raw(Json.Encode(Model))’ />

Refer https://highspeedlowdrag.wordpress.com/2014/08/23/mvc-data-to-jquery-data/

请参阅https://highspeedlowdrag.wordpress.com/2014/08/23/mvc-data-to-jquery-data/

I did below and it works like charm.

我在下面做了,它就像魅力一样。

<input id="hdnElement" class="hdnElement" type="hidden" value='@Html.Raw(Json.Encode(Model))'>

<输入id="hdnelement" class="hdnElement" type="hidden" value="@Html.Raw(Json.Encode(Model)))">

#7


0  

Extending the great answer from Dave. You can create a simple HtmlHelper.

戴夫回答得很好。您可以创建一个简单的HtmlHelper。

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

And in your view:

在你的观点:

@Html.RenderAsJson(Model)

This way you can centralize the logic for creating the JSON if you, for some reason, would like to change the logic later.

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

#8


0  

Andrew had a great response but I wanted to tweek it a little. The way this is different is that I like my ModelViews to not have overhead data in them. Just the data for the object. It seem that ViewData fits the bill for over head data, but of course I'm new at this. I suggest doing something like this.

安德鲁得到了很好的回应,但我想再多说一点。不同的是,我希望我的模型视图中不包含开销数据。只是对象的数据。看起来,ViewData正好符合了head数据的要求,但是我当然是新手了。我建议做这样的事。

Controller

控制器

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

View

视图

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

What This does for you is it gives you the same data in your JSON as in your ModelView so you can potentially return the JSON back to your controller and it would have all the parts. This is similar to just requesting it via a JSONRequest however it requires one less call so it saves you that overhead. BTW this is funky for Dates but that seems like another thread.

它为你做的是它在你的JSON中给你和在你的ModelView中一样的数据所以你可以把JSON返回给你的控制器它会有所有的部分。这类似于通过JSONRequest请求它,但是它需要一个更少的调用,因此它可以节省开销。顺便说一句,这对于约会来说很时髦,但这似乎是另一种思路。