2009-09-15 7 views
7

Mam niestandardowy viewmodel, który serializowany przy użyciu JsonResult. ViewModel ma pewne właściwości, które muszą być publiczne, ale jednocześnie te właściwości nie powinny być widoczne w wynikowym wyjściu Json.Jak wyłączyć niektóre seriale publiczne z serializacji w JsonResult?

Próbowałem już użyć atrybutu [NonSerialized], ale to nie miało żadnego efektu.

Czy istnieje prosty sposób na zrobienie tego? Czy musiałbym zakodować własny typ wyniku (w takim przypadku prawdopodobnie nie będę się tym przejmował)?

+0

Większość odpowiedzi polega na użyciu atrybutów lub wrappów. Chcę po prostu wyłączyć niektóre właściwości publiczne podczas serializacji. Szukam JSON.NET zgodnie z sugestią @Charlino, ale nie znalazłem sposób. Jest tak w przypadku: Mam właściwość 'Błąd', która będzie ustawiona tylko w przypadku wystąpienia błędu. strona klienta sprawdzi, czy pierwsza wyświetla komunikat, w przeciwnym razie wyświetli resztę właściwości Model. Gdy nie ma błędu, wyrenderuje '{...," Error ": null}'! – CallMeLaNN

Odpowiedz

24

Możesz umieścić atrybut [ScriptIgnore] na elementach, które nie powinny być serializowane. Zobacz przykład ScriptIgnoreAttribute Class in MSDN.

+8

dla innych tam pełna przestrzeń nazw atrybutu to [System.Web.Script.Serialization.ScriptIgnore] – EBarr

+0

Wydaje się, że 'ScriptIgnore' przy użyciu zwykłego MVC' return Json() '--- then' JsonIgnore' przy użyciu 'Json.NET' – mmcrae

0

Niezupełnie odpowiedź szukasz, ale można oszukać Json() stosując następujący kod i anonimowych klas:

MyModel model = ...; 
return Json(new MyModel {model.Prop1, model.Prop2}); 
+0

Wiem, że mogę zamiast tego używać typów anonimowych. Ale to sprawia, że ​​testowanie jednostkowe wyniku jest znacznie trudniejsze. Oznacza to, że musiałbym przeanalizować wynik serializowany lub użyć refleksji. –

+0

Testowanie jednostek JsonResults jest trudne. Jak to robiłeś wcześniej? Wygląda na to, że nie można pobrać podstawowego modelu, który napędzał JsonResult. –

+1

To nie jest żaden problem. właściwość JsonResult.Data zawiera obiekt, który ma zostać przekształcony do postaci szeregowej. Ponieważ używam niestandardowego viewmodelu zamiast anonimowego typu obiektu, mogę po prostu pobrać ten obiekt i przetestować jego właściwości. –

0

Można utworzyć klasy otoki, który udostępnia tylko te właściwości, które mają w JsonResult. W poniższym przykładzie krowa ma 2 właściwości - "Noga" i "Moo". Załóżmy, że chcesz tylko wystawiać "Nogi" jako własność. Następnie

Dim cis jak CowWrapper = Nowa CowWrapper (C)

powróci klasę opakowaniu, które tylko odsłania "leg". Jest to również przydatne w przypadku obiektów takich jak DataGridView, jeśli chcesz wyświetlić tylko niektóre podzestawy właściwości.

Klasa publiczna Krowa

Public ReadOnly Property Noga() As String

get 

     return "leg" 

    end get 

koniec Property

Public ReadOnly Property Moo() As String

get 

     return "moo" 

    end get 

koniec Property

klasa koniec

Klasa publiczna CowWrapper

Private m_cow as Cow = Nothing 

Public Sub New(ByVal cow as Cow) 

    m_cow = cow 

end Sub 


    m_cow = cow 

Public ReadOnly Property Noga() As String

get 

     return m_cow.Leg() 

    end get 

koniec Property

koniec klasy

+0

To działa, ale za cenę konieczności skopiowania kilku właściwości, więc nie jest to naprawdę to, czego szukałem. –

+0

Przy jakim koszcie? Programowanie? Powinno być proste napisanie prostego narzędzia do skonstruowania tych klas, biorąc pod uwagę plik klasy jako dane wejściowe, lub napisanie klasy, która może dynamicznie budować właściwości za pomocą introspekcji. Runtime? Koszt dodatkowego odniesienia jest pomijalny. –

+0

Nie zdawałem sobie sprawy, że chodzi ci o konstruowanie takich typów w czasie wykonywania przez odbicie. To oczywiście obejmowałoby wszystkie moje niestandardowe typy widoku bez dodatkowego kodowania. Prawidłowe podejście, ale jest zbyt skomplikowane w porównaniu do użycia gotowego narzędzia (mianowicie Json.Netto) –

1

rozszerzyć klasę JavaScriptConverter do nie zawierają prope rty z NonSerializedAttribute. Następnie możesz utworzyć niestandardową ActionResult, która używa Twojego JavaScriptConverter do serializacji obiektu.

To tworzy solidną i sprawdzalną klasę bez konieczności (ponownego) generowania klas opakowania lub korzystania z anonimowych obiektów.

+0

Takie podejście również przyszło mi do głowy. To na pewno działa, ale ponieważ chodzi tu tylko o zapisanie kilku bajtów każdego żądania Json, miałem nadzieję, że jest coś prostszego. Dobre podejście, ale po prostu za dużo pracy w porównaniu do korzyści w moim przypadku. –

2

Spójrz na JSON.NET od James Newton-King. Zrobi to, czego szukasz.

+0

Idealny! Jak się okazuje, James napisał również pasujący typ JsonResult: http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net.aspx –

2

Wystarczy utworzyć interfejs, aby powrócić zamiast klasy.

public interface IMyViewModel { 
    string MyPublicProperty { get; set; } 
} 

Następnie należy utworzyć klasę, która dziedziczy jest przez urządzenie

public class MyViewModel : IMyViewModel { 
    public string MyPublicProperty { get; set; } 
    public string MyNotSoPublicProperty { get; set; } 
} 

i powrócić do interfejsu, a nie klasy, w akcji kontrolera

public JsonResult MyJson(){ 
    IMyViewModel model = new MyViewModel(); 
    return Json(model); 
} 

i otrzymaną JSON będzie

{ 
    'MyPublicProperty': '' 
} 

Jednym z wyzwań w skryptach po stronie klienta jest to, że jeśli zmieniasz swoje zajęcia, nie masz pojęcia, czy niszczysz implementację po stronie klienta, czy też nie. Jeśli używasz typów interfejsu w swoim JSON, rozumiesz, że jeśli zmienisz interfejs, robisz coś, co potencjalnie może zabijać implementację po stronie klienta. A także oszczędza od podwójnego sprawdzania strony klienta na próżno, jeśli zmieniasz coś, co NIE jest w inteface (w związku z tym nie jest serializowane).

Również wiele razy Twoje modele ViewModels mogą zawierać duże kolekcje lub złożone typy, które niekoniecznie muszą być wyprowadzane na kliencie. Może to zająć dużo czasu serializacji lub ujawnienia informacji, które po prostu nie należą do kodu klienta. Używanie interfejsów sprawi, że będzie on bardziej przejrzysty, aby wiedzieć, co jest na wyjściu.

Ponadto użycie atrybutów takich jak [ScriptIgnore] w usłudze ma zastosowanie tylko do określonego scenariusza (szeregowania JavaScript), który zmusza do stawienia czoła dokładnie temu samemu problemowi, na przykład w przypadku późniejszego serializowania do formatu XML. To niepotrzebnie zaśmieciłoby twoje modele widoków tonami atrybutów. Ilu z nich naprawdę chcesz tam? Używanie intefaces ma zastosowanie wszędzie, a żaden moduł viewmodel nie musi być zaśmiecony dodatkowymi atrybutami.

+0

Dzięki za odpowiedź. Nie jest to zła metoda, ale istnieje również bardziej zautomatyzowany sposób, aby upewnić się, że klasy po stronie klienta są nadal zsynchronizowane ze stroną serwera: Użyj funkcji Typescript dla kodu po stronie klienta i programowo generuj modele widoku po stronie klienta z obiektów po stronie serwera podczas kompilacji. Więcej informacji można znaleźć na stronie http://type.litesolutions.net/. –

+0

Czy to podejście działa z serializacją listy ? Nie mogę sprawić, żeby to działało ... – tomasofen

Powiązane problemy