views:

420

answers:

5

Hi,

I have a custom viewmodel which serialized using a JsonResult. The ViewModel has some properties which have to be public, but at the same time these properties should not be visible in the resulting Json output.

I've already tried using the [NonSerialized] attribute, but that did not seem to have any effect.

Is there any simple way to do this? Or would I have to code my own result type (in which case I probably won't bother)?

A: 

Not exactly the answer you're looking for, but you can cheat Json() using the following code and anonymous classes:

MyModel model = ...;
return Json(new MyModel {model.Prop1, model.Prop2});
David Andres
I know I can use anonymous types instead. But that makes unit testing the result much harder. It means I'd either have to parse the serialized result or use reflection.
Adrian Grigore
Unit testing JsonResults is tough to begin with. How were you doing this before? It doesn't look like you can retrieve the underlying model that drove the JsonResult.
David Andres
That's no problem at all. the JsonResult.Data property contains the object that is to be serialized. Since I am using a custom viewmodel instead of an anonymous object type, I can simply grab that object and test it's properties.
Adrian Grigore
Well, though painful, you could always create a new version of your class and simply copy those properties you want. I've edited my post with this approach.
David Andres
@Adrian: Thanks, I didn't know that Data referred to the serialized object.
David Andres
A: 

You can create a wrapper class that exposes only those properties that you want in the JsonResult. In the example below, Cow has 2 properties - "Leg" and "Moo". Suppose you want to only expose "Leg" as a property. Then

Dim cw as CowWrapper = New CowWrapper(c)

will return a wrapper class that only exposes "Leg". This is also useful for things like DataGridView if you only want to display some subset of the properties.

Public Class Cow

Public ReadOnly Property Leg() as String

   get

      return "leg"

   end get

end Property

Public ReadOnly Property Moo() as String

   get

      return "moo"

   end get

end Property

end class

Public Class 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 Leg() as String

   get

      return m_cow.Leg()

   end get

end Property

end Class

Larry Watanabe
This works, but at the price of having to copy quite a few properties, so it's not really what I was looking for.
Adrian Grigore
At what cost? Programming? It should be simple to write a simple utility to construct these classes given the class file as input, or to write a class that can construct the properties dynamically using introspection. Runtime? The cost of an extra reference is neglible.
Larry Watanabe
I did not realize you mean constructing such types at runtime via reflection. That would of course cover all of my custom viewmodel types without any additional coding. A valid approach but it's too complicated in comparison to using a ready-made tool (namely Json.Net)
Adrian Grigore
Great! (That there is a ready-made tool). I should have written "it should be possible" not "it should be simple" .. as I don't actually know much about introspection myself.I've used the wrapper classes (hard coded, not using introspection) when populating a DataGridView with a LINQ to SQL class. Often I don't want to display all fields in the table, so the wrapper takes care of this.
Larry Watanabe
+1  A: 

Extend the JavaScriptConverter class to not include properties with the NonSerializedAttribute. Then you can create a custom ActionResult that uses your JavaScriptConverter to serialize the object.

This creates a solid and testable class without having to (re)generate wrapper classes or using anonymous objects.

Ronald
That's the approach that also came to my mind. It certainly works, but since this is only about saving a few bytes of each Json request, I was hoping there's something simpler. Good approach, but simply too much work compared to the benefits in my case.
Adrian Grigore
+1  A: 

Have a look at JSON.NET from James Newton-King. It'll do what you're looking for.

HTHs
Charles

Charlino
Perfect! As it turns out, James has also written a matching JsonResult type: http://james.newtonking.com/archive/2008/10/16/asp-net-mvc-and-json-net.aspx
Adrian Grigore
+3  A: 

You can put a [ScriptIgnore] attribute on the members that shouldn't be serialized. See http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx for an example.

JacobE
for others out there the full namespace of the attribute is [System.Web.Script.Serialization.ScriptIgnore]
EBarr