View Model ASP.NET MVC JSON nesnesine dönüştürmek nasıl?


156

.NET için yeni bir Java geliştiricisiyim. Bir widget sarmak için kısmi bir görünüm istiyorum bir .NET MVC2 projesi üzerinde çalışıyorum. Her JavaScript widget nesnesinin model verileri tarafından doldurulacak bir JSON veri nesnesi vardır. Sonra bu verileri güncelleştirme yöntemleri, pencere öğesinde veri değiştirildiğinde veya bu veri başka bir pencere öğesinde değiştirildiğinde olaylara bağlanır.

Kod şuna benzer:

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>

Ne bilmiyorum nasıl üzerinden veri göndermek SomeModelViewve daha sonra widget doldurmak ve JSON dönüştürmek için bunu kullanmak mümkün. Bunu kontrolörde yapmanın bazı basit yollarını görmüştüm ama görünüşte değil. Bunun temel bir soru olduğunu düşünüyorum ama birkaç saattir bu kaygan yapmaya çalışıyorum.


1
Bunun eski bir soru olduğunu biliyorum. Ancak bugün itibariyle bunu yapmanın daha iyi yolları var. JSON'u satır içi Görüntüleme sonucunuzla karıştırmayın. JSON, AJAX aracılığıyla kolayca seri olarak sunulur ve nesneler gibi işlenebilir. JavaScript'teki her şey Görünüm'den ayrı olmalıdır. Bir Denetleyici ile herhangi bir çaba harcamadan modelleri kolayca iade edebilirsiniz.
Piotr Kula

Yanıtlar:


346

Jvc ile mvc3 @Html.Raw(Json.Encode(object))hile yapmak gibi görünüyor.


1
+1 Html.Raw kullandım, ancak Json.Encode'u hiç bulamadım ve sadece denetleyicideki dizeyi görünüm modeline eklemek için JavaScriptSerializer'ı kullandım
AaronLS

5
Bu yaklaşım, sonuçtaki JSON'u Javascript'e geçirmek istediğinizde bile çalışır. @ Html.Raw (...) kodunu <script> etiketlerinin içine bir işlev parametresi olarak koyarsanız, Razor yeşil dalgalı çizgilerden şikayet eder, ancak JSON gerçekten de çağrılan JS'ye yapar. Çok kullanışlı ve kaygan. +1
Carl Heinrich Hancke

1
MVC3'ten beri bunu yapmanın yolu budur ve bir denetleyiciden iade edilmelidir. Json'u Viewresult'unuza yerleştirmeyin. Bunun yerine JSON'u ayrı ayrı işlemek için bir denetleyici yapın ve AJAX aracılığıyla bir JSON isteği yapın. Görünümde JSON gerekiyorsa yanlış bir şey yapıyorsun. Bir ViewModel veya başka bir şey kullanın.
Piotr Kula

3
Json.Encode, 2 boyutlu dizimi json'daki 1 boyutlu diziye kodlar. Newtonsoft.Json.JsonConvert.SerializeObject iki boyutu düzgün bir şekilde json'a serileştirir. Bu yüzden ikincisini kullanmanızı öneririm.
mono68

12
MVC 6 (belki de 5) Json.Serializekullanırken, Kodlama yerine kullanmanız gerekir .
16:39

31

Aferin, sadece MVC kullanmaya başladın ve ilk büyük kusurunu buldun.

Görünümde gerçekten JSON'a dönüştürmek istemiyorsunuz ve bu konumların hiçbiri mantıklı olmadığından, gerçekten denetleyicide dönüştürmek istemiyorsunuz. Ne yazık ki, bu durumla sıkışıp kaldınız.

Yaptığım en iyi şey JSON'u bir ViewModel'deki görünüme göndermek, şöyle:

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

return View("viewname", viewModel);

sonra kullan

<%= Model.JsonData %>

sizin görüşünüze göre. Standart .NET JavaScriptSerializer'ın oldukça saçma olduğunu unutmayın.

kontrol cihazında en azından test edilebilir yapar (tam olarak yukarıdaki gibi olmasa da - muhtemelen bir ISerializer'ı bağımlılık olarak almak istersiniz, böylece alay edebilirsiniz)

Ayrıca, JavaScript'inizle ilgili olarak güncelleyin , yukarıdaki TÜM widget JS'yi şu şekilde sarmak iyi bir uygulamadır:

(
    // all js here
)();

Bu şekilde bir sayfaya birden çok pencere öğesi koyarsanız, çakışmalara neden olmazsınız (yöntemlere sayfanın başka bir yerinden erişmeniz gerekmedikçe, ancak bu durumda pencere bileşenini yine de bazı pencere öğesi çerçevesiyle kaydettirmeniz gerekir). Şimdi bir sorun olmayabilir, ancak gelecekte bir gereksinim olduğunda kendinizi mukus çabasından kurtarmak için köşeli parantez eklemek iyi bir uygulama olacaktır, aynı zamanda işlevselliği kapsüllemek için iyi OO uygulamasıdır.


1
Bu ilginç görünüyor. Ben sadece json olarak verilerin bir kopyasını yapmak ve viewData olarak geçecekti ama bu şekilde daha ilginç görünüyor. Bununla oynayacağım ve size haber vereceğim. BTW bu benim ilk kez stackoverflow hakkında bir soru gönderme ve iyi yanıtlar almak için what..5 dakika sürdü, bu harika !!
Chris Stephens

onunla yanlış bir şey yok, onun özelleştirilebilir değil, eğer herhangi bir özel değer biçimlendirme istiyorsanız elden önce yapmak zorunda, temelde her şeyi bir dize yapmak :( bu tarihler ile en belirgindir. kolay geçici çözümler olduğunu biliyorum, ama olmamalı gerekli
Andrew Bullock

@ Güncelleme Benzersiz bir nesne adı oluşturmak için bu widget'ın bir .net statik sayacı kullanma hakkında gidiyordu. Ama yazdıklarınız aynı şeyi başaracak ve daha ince yapacak gibi görünüyor. Ayrıca onları izlemek için bir sayfa düzeyi nesneye bir widget "new_widget_event 'oluşturulması bağlama baktım ama bunu yapmanın orijinal nedeni OBE oldu. Bu yüzden daha sonra tekrar ziyaret edebilirim. Ben göndereceğim tüm yardım için teşekkürler önerdiğiniz şeyin değiştirilmiş bir versiyonu, neden daha iyi sevdiğimi açıklıyor
Chris Stephens

2
benim önceki ifade "onunla yanlış bir şey yok" geri. Bunda yanlış olan her şey var.
Andrew Bullock

Neden JSON'u denetleyiciden döndüremeyeceğimizi söylüyorsunuz? Bunun böyle yapılması gerekiyordu. Aynı serileştiricileri kullanmak JavaScriptSerializerveya Return Json(object)her ikisini birden kullanmak. Ayrıca, aynı JSON'u denetleyiciye geri göndermek, doğru modeli tanımladığınız sürece nesneyi sizin için yeniden oluşturur. Belki MVC2 sırasında büyük bir dezavantaj oldu .. ama bugün onun bir esinti ve çok uygun. Cevabınızı bunu yansıtacak şekilde güncellemelisiniz.
Piotr Kula

18

Bu şekilde yapmak için oldukça güzel buldum (görünümde kullanım):

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

Uzantı sınıfına göre ilgili yardımcı yöntem:

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

Süper sofistike değil, ama nereye koyacağımız sorununu çözüyor (Kontrolörde veya görüşte mi?) Cevap açıktır: ikisi de;)


Bu güzel ve temiz bence ve yeniden kullanılabilir bir yardımcı sarılmış. Şerefe, J
John

6

JsonEylemden doğrudan kullanabilirsiniz ,

Eyleminiz şöyle bir şey olurdu:

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

Düzenle

Sadece bu Modelbir Görünüm olduğunu varsayalım, bu yüzden yukarıdaki kesinlikle doğru değil, bunu elde etmek için Ajaxdenetleyici yöntemine bir çağrı yapmak ascxzorunda kalacaksınız, o zaman kendi başına bir modelim olmazdı, kodumu bırakacağım sizin için yararlı olması durumunda ve çağrıyı değiştirebilirsiniz.

Edit 2 sadece kodu koydum


1
ama bunu görüntüye dönüştüremaz, 2. bir ajax çağrısı yapmak zorunda kalacak
Andrew Bullock

Teşekkürler, ben aslında bunu bir jQuery get json çağrısı kullanarak yapıyordum ve HTML öğelerinin kendileri json'dan doldurmasını planlıyordum. Bununla birlikte, şu anda izlediğimiz desen, görünümlerimizin bir modelView döndürmesi ve tablolar vb. Gibi temel HTML öğelerini doldurmanın en kolay yoludur.
Chris Stephens

2
JSON'u bir Görünüm Sonucu ile gömmemelisiniz. OP'nin uygulanan standart MVC'ye bağlı kalması ve bir model veya viewmodel döndürmesi veya bir AJAX yapması gerekir. Bir görünümü ile JSON gömmek için kesinlikle hiçbir neden yoktur. Bu çok kirli bir kod. Bu yanıt, Microsoft Practices tarafından doğru ve önerilen yoldur. Downvote gereksizdi bu kesinlikle doğru cevap. Kötü kodlama uygulamalarını teşvik etmemeliyiz. AJAX üzerinden JSON veya Views üzerinden Modeller. Kimse karışık biçimlendirme ile spagetti kodunu sevmez!
Piotr Kula

Bu çözüm aşağıdaki soruna neden olacaktır: stackoverflow.com/questions/10543953/…
Jenny O'Reilly

2

@ Html.Raw (Json.Encode (nesne)) Görünüm Kalıcı Nesnesini JSON'a dönüştürmek için kullanılabilir


1

Dave'in büyük cevabını genişletmek . Basit bir HtmlHelper oluşturabilirsiniz .

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

Ve sizce:

@Html.RenderAsJson(Model)

Bu nedenle, mantığı daha sonra değiştirmek isterseniz, JSON'u oluşturmak için mantığı merkezileştirebilirsiniz.



0

Andrew'un harika bir yanıtı vardı ama biraz tweek etmek istedim. Bu farklı bir şekilde, benim ModelViews onları havai veri yok gibi olmasıdır. Yalnızca nesnenin verileri. ViewData, kafa üstü veriler için faturaya uyuyor gibi görünüyor, ancak elbette bu konuda yeniyim. Böyle bir şey yapmanı öneririm.

kontrolör

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

Görünüm

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

Bunun sizin için yaptığı şey, JSON'unuzda ModelView'inizle aynı verileri vermesidir, böylece JSON'u denetleyicinize geri döndürebilirsiniz ve tüm parçalara sahip olabilirsiniz. Bu sadece bir JSONRequest üzerinden talep etmeye benzer, ancak daha az bir çağrı gerektirir, bu yüzden o ek yükü korur. BTW bu Tarihler için korkak ama başka bir iş parçacığı gibi görünüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.