ASP.NET MVCでビューモデルをJSONオブジェクトに変換する方法


156

私は.NETを初めて使用するJava開発者です。ウィジェットをラップするための部分的なビューが必要な.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インラインとビュー結果を混在させないでください。JSONはAJAXを介して簡単にシリアル化され、オブジェクトのように扱うことができます。JavaScriptのすべては、ビューから分離する必要があります。コントローラを使用することなく、簡単にモデルを返すことができます。
Piotr Kula 2013年

回答:


346

かみそりを使用したMVC3の場合 @Html.Raw(Json.Encode(object))、トリックを行うようです。


1
+1 Html.Rawを使用しましたが、Json.Encodeが見つからず、JavaScriptSerializerを使用してコントローラーの文字列をビューモデルに追加しました
AaronLS '31

5
このアプローチは、結果のJSONをJavaScriptに渡したい場合でも機能します。@ Html.Raw(...)コードを<script>タグ内の関数パラメーターとして置くと、Razorは緑色の波線で不平を言いますが、JSONは実際に呼び出されたJSにそれを行います。とても便利で滑らか。+1
カールハインリッヒハンケ2012

1
これはMVC3以降の方法であり、コントローラーから返される必要があります。jsonをViewresultに埋め込まないでください。代わりに、JSONを個別に処理するコントローラーを作成し、AJAX経由でJSONリクエストを実行します。ビューにJSONが必要な場合は、何か問題があります。ViewModelなどを使用します。
Piotr Kula 2013年

3
Json.Encodeは、2次元配列をjsonの1次元配列にエンコードします。Newtonsoft.Json.JsonConvert.SerializeObjectは、2つの次元を適切にjsonにシリアル化します。したがって、後者を使用することをお勧めします。
mono68、2015

12
MVC 6(多分5)を使用する場合Json.Serializeは、Encodeの代わりに使用する必要があります。
KoalaBear 2016

31

よくできました。MVCを使い始めたばかりで、最初の大きな欠陥を見つけました。

これらの場所はどちらも意味がないため、ビューで実際にJSONに変換する必要はなく、コントローラーで変換する必要もありません。残念ながら、このような状況に陥っています。

私が見つけた最善のことは、次のように、ViewModelのビューにJSONを送信することです。

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

このように、ページに複数のウィジェットを配置した場合、競合は発生しません(ページの他の場所からメソッドにアクセスする必要がない限り、その場合はウィジェットを何らかのウィジェットフレームワークに登録する必要があります)。今は問題にならないかもしれませんが、ブラケットを追加して、将来的に要件が大きくなったときの労力を節約できるようにすることをお勧めします。また、機能をカプセル化することもオブジェクト指向の優れた方法です。


1
面白そうですね。データのコピーをjsonとして作成し、それをviewDataとして渡すだけでしたが、この方法の方が興味深いように見えます。私はこれで遊んで、あなたに知らせます。ところでこれは、stackoverflowに質問を投稿するのが初めてで、良い応答を得るのに5分ほどかかりました。
Chris Stephens

何も問題はありませんが、カスタマイズできません。カスタム値の書式設定が必要な場合は、事前に行う必要があります。基本的にすべてを文字列にします(これは日付で最も目立ちます。簡単な回避策があることはわかっていますが、必要です!
Andrew Bullock 2010

@Updateウィジェットの.net静的カウンターを使用して一意のオブジェクト名を生成する方法を確認しました。しかし、あなたが書いたものはそれが同じことを達成し、それを滑らかにするように見えます。また、ウィジェット「new_widget_event」の作成をページレベルのオブジェクトにバインドしてそれらを追跡することも検討しましたが、それを行う本来の理由はOBEになりました。後で再検討するかもしれません。投稿するすべての助けに感謝あなたが提案したものの修正バージョンですが、なぜ私がそれをより良くするのかを説明します
Chris Stephens

2
私は以前の声明を撤回しました。すべてが間違っています。
Andrew Bullock

コントローラーからJSONを返すことができないと言うのはなぜですか。それがその方法です。使用JavaScriptSerializerまたはReturn Json(object)両方とも同じシリアライザを使用します。また、同じJSONをコントローラーにポストバックすると、正しいモデルを定義している限り、オブジェクトが再構築されます。たぶんMVC2の間にそれは主要な欠点だったかもしれません。これを反映するには、回答を更新する必要があります。
Piotr Kula 2013年

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

それは非常に洗練されていませんが、それをどこに配置するかという問題を解決します(コントローラー内またはビュー内?)答えは明らかに:どちらでもありません;)


これは私の意見では素晴らしく、きれいで、再利用可能なヘルパーに包まれました。乾杯、J
ジョン

6

Jsonアクションから直接使用でき、

あなたの行動は次のようになります:

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

編集する

これはModelビューであると想定しているので、上記は厳密には正しくありませAjaxん。これを取得するには、コントローラーメソッドを呼び出す必要があります。ascxモデル自体はありません。コードはそのままにします。万が一に備えて電話を修正できるように

編集2 はコードにIDを入れるだけです


1
しかし、彼はこれをビューにレンダリングできません。彼は2回目のajax呼び出しを行う必要があります
Andrew Bullock

おかげで、私はもともとjQuery get json呼び出しを使用してこれを行っていましたが、HTML要素にjsonからそれらを挿入することを計画していました。ただし、現在私たちがフォローしているパターンは、ビューがmodelViewを返すことであり、これはテーブルなどの基本的なHTML要素を入力する最も簡単な方法です。ViewDataと同じデータをJSON形式で送信することもできますが、無駄に見えます。
Chris Stephens

2
YOuはJSONをビュー結果に埋め込むべきではありません。OPは、実践されている標準のMVCに準拠してモデルまたはビューモデルを返すか、AJAXを実行する必要があります。JSONをビューに埋め込む理由はまったくありません。それは非常に汚いコードです。この答えは正しい方法であり、Microsoft Practicesが推奨する方法です。反対票は不要でした。これは間違いなく正しい答えです。私たちは悪いコーディング慣行を奨励すべきではありません。AJAX経由のJSONまたはビュー経由のモデル。マークアップが混在するスパゲッティコードは誰も好きではありません!
Piotr Kula 2013年

このソリューションでは、次のような問題になります:stackoverflow.com/questions/10543953/...
ジェニー・オライリー



0

デイブからの素晴らしい答えを拡張します。単純なHtmlHelperを作成できます。

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

そしてあなたの見解では:

@Html.RenderAsJson(Model)

このようにして、何らかの理由で後でロジックを変更したい場合に、JSONを作成するためのロジックを集中化できます。


0

アンドリューは素晴らしい反応を示しましたが、少し調整したいと思いました。これが異なる点は、ModelViewにオーバーヘッドデータが含まれないようにすることです。オブジェクトのデータのみ。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を介して要求するのと似ていますが、呼び出しが1つ少ないため、オーバーヘッドを節約できます。ところでこれはDatesにとってファンキーですが、それは別のスレッドのようです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.