2009-09-15 51 views
7

我有一個使用JsonResult序列化的自定義viewmodel。 ViewModel有一些必須公開的屬性,但同時這些屬性在結果Json輸出中不可見。如何排除某些公共屬性被序列化爲JsonResult?

我已經嘗試過使用[NonSerialized]屬性,但這似乎沒有任何效果。

有沒有簡單的方法來做到這一點?或者我必須編寫自己的結果類型(在這種情況下,我可能不會打擾)?

+0

大部分的答案是使用屬性或包裝無論什麼。我只想在序列化過程中簡單地排除一些公共屬性。我正在尋找@Charlino建議的JSON.NET,但沒有找到方法。情況就是這樣:我有'錯誤'屬性,它只會在錯誤發生時設置。客戶端將首先檢查此消息,否則將顯示Model屬性的其餘部分。當沒有錯誤時,它會呈現'{...,「Error」:null}'! – CallMeLaNN 2011-05-12 08:57:10

回答

24

您可以將[ScriptIgnore]屬性放在不應序列化的成員上。以ScriptIgnoreAttribute Class in MSDN爲例。

+8

該屬性的完整命名空間是[System.Web.Script.Serialization.ScriptIgnore] – EBarr 2010-09-18 18:41:47

+0

當使用常規MVC時,似乎'ScriptIgnore'返回Json()',然後是'JsonIgnore',如果使用'Json.NET' – mmcrae 2018-03-01 20:21:43

0

不正是你要找的,但你可以用下面的代碼和匿名類作弊Json()答案:

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

我知道我可以使用匿名類型。但是這讓單元測試結果變得更加困難。這意味着我要麼解析序列化的結果,要麼使用反射。 – 2009-09-15 18:37:27

+0

單元測試JsonResults很難開始。你過得怎麼樣?它看起來不像你可以檢索驅動JsonResult的底層模型。 – 2009-09-15 18:54:41

+1

這完全沒有問題。 JsonResult.Data屬性包含要序列化的對象。由於我使用自定義視圖模型而不是匿名對象類型,因此我可以簡單地抓住該對象並測試它的屬性。 – 2009-09-16 10:30:25

0

您可以創建一個公開只是你在想這些屬性的包裝類JsonResult。在下面的例子中,Cow有兩個屬性 - 「腿」和「Moo」。假設您只想將「Leg」作爲屬性公開。然後

昏暗CW作爲CowWrapper =新CowWrapper(C)

會返回一個包裝類,只公開 「腿」。如果你只想顯示一些屬性的子集,這對DataGridView等也很有用。

公共類牛

公共ReadOnly屬性腿()作爲字符串

get 

     return "leg" 

    end get 

端屬性

公共ReadOnly屬性武()作爲字符串

get 

     return "moo" 

    end get 

端屬性

端類

公共類CowWrapper

Private m_cow as Cow = Nothing 

Public Sub New(ByVal cow as Cow) 

    m_cow = cow 

end Sub 


    m_cow = cow 

公共ReadOnly屬性腿()作爲字符串

get 

     return m_cow.Leg() 

    end get 

端屬性

端類

+0

這個工作,但在不得不復制不少屬性的代價,所以它不是我真正想要的。 – 2009-09-15 18:40:46

+0

費用是多少?編程?編寫一個簡單的實用程序來構造這些類,給定類文件作爲輸入,或者編寫一個可以使用內省動態構造屬性的類應該很簡單。 運行時間?額外參考的成本是微不足道的。 – 2009-09-15 19:04:14

+0

我沒有意識到你的意思是在運行時通過反射來構造這樣的類型。那當然會覆蓋我所有的自定義視圖模型類型,而不需要任何額外的編碼。這是一種有效的方法,但與使用現成工具(即Json)相比,它太複雜了。淨) – 2009-09-16 10:37:24

1

擴展JavaScriptConverter類不包括prope與NonSerializedAttribute。然後,您可以創建一個自定義ActionResult,使用您的JavaScriptConverter序列化對象。

這創建了一個堅實且可測試的類,而不必(重新)生成包裝類或使用匿名對象。

+0

這也是我想到的方法。它當然有效,但由於這只是爲了節省每個Json請求的幾個字節,所以我希望有一些更簡單的方法。好的方法,但與我的情況相比,只是工作太多。 – 2009-09-16 10:33:04

2

看看James Newton-King的JSON.NET。它會做你想要的。

+0

完美!事實證明,James還編寫了一個匹配的JsonResult類型:http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net.aspx – 2009-09-16 10:34:32

2

只需創建一個接口,而不是返回一個類。

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

然後創建一個繼承接口

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

類和返回的接口,而不是類,在控制器動作

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

,所得JSON將

{ 
    'MyPublicProperty': '' 
} 

客戶端腳本的一個挑戰是,如果你改變你的類,你不知道你是否在破壞客戶端的實現。如果你在JSON中使用接口類型,你就會明白,如果你改變接口,你正在做一些可能會殺死客戶端實現的東西。而且,如果你正在改變不在界面中的東西(因此不會被序列化),它也可以避免雙重檢查客戶端。

而且,很多時候,你的ViewModels可能有大的集合或複雜類型的人身上,你不一定要輸出到客戶端。這些可能需要很長時間才能序列化或暴露不屬於客戶端代碼的信息。使用接口將使它更加透明地知道輸出中的內容。

另外,對屬性使用諸如[ScriptIgnore]之類的屬性僅適用於特定場景(JavaScript序列化),如果您稍後序列化爲XML,則迫使您面對完全相同的問題。這會不必要地浪費你的視圖模型有很多屬性。那裏有多少人真的想要?使用intefaces適用於任何地方,並且viewmodel不需要額外的屬性。

+0

感謝您的回答。這不是一個壞方法,但也有一種更自動化的方法來確保您的客戶端類仍與服務器端保持同步:使用Typescript作爲客戶端代碼,並以編程方式從服務器端對象生成客戶端視圖模型編譯期間。有關更多詳細信息,請參閱http://type.litesolutions.net/。 – 2014-04-01 06:40:38

+0

這種方法是否可以與List 進行序列化?我無法做到這一點... – tomasofen 2014-05-28 10:29:22

相關問題