views:

1387

answers:

6

If I'm rendering a regular view in asp.net mvc the only domain object properties that show up in my page the ones I specifically write out. For example:

<div><%= Customer.FirstName %></div>

However, if I serialize a domain object for json it will include every property. Example:

public JsonResult Customer (int? id)
{
    Customer customer = _serviceLayer.GetCustomer (id.Value);

    return Json (customer);
}

Since I don't want every Customer property exposed what is the best way to filter the output properties for json in this case? Can you use an include/exclude list like UpdateModel()? Use a proxy class such as public class JsonCustomer? What would you recommend?

+10  A: 

I use anonymous types for this:

var customer = from c in serviceLayer.GetCustomers()
               where c.Id == id.Value
               select new { FirstName = c.FirstName };

This is not just a good idea. Rather, it's protection against the exception that you will get when calling Json() if your object graph contains a circular reference.

Craig Stuntz
+1  A: 

You could use the Newtonsoft library and [JsonIgnore] attribute for marking properties of your class you don't want to expose. There are other libraries (with possible different property ignore attribute name), I personally prefer this one since it's very flexible in JSON converter extensions etc + it can easily serialize anonymous objects.

public class Customer
{
    ...
    [JsonIgnore]
    public string UrlIn { get; set; }
    public string FirstName { get; set; }
    // following example of a converter, you could write your own as well
    [JsonConverter(typeof(Newtonsoft.Json.Converters.JavaScriptDateTimeConverter))]
    public DateTime Created { get { return _created; } }
}
aprilchild
I thought about this but on the Admin section I would want a different set of properties.
Todd Smith
I wouldn't include a new third-party library just for solving this problem.
JacobE
the link is broken?
BenB
+1  A: 

Please use a view model. A view model is an object that the UI uses to represent your domain objects on the screen. Each screen has its own view model.

When you make your view model, which is a DTO, which is a flattened, null-safe projection of domain objects, do not map properties you do not wish to be displayed on the screen.

Serialize the view model, not your domain object.

Matt Hinze
Can you elaborate or link to an example?
Cherian
This is a good idea, in general - and what I was doing when this occured. My problem was using a view model that had Entities, complex objects as properties. The serializer went through and found some parent->child->parent references deep in the view model. MY TIP - Keep view models flat, and simple as possible! Load simple types (string, date, int, etc) from data in the controller into the view model.
Jason
A: 

I ran into the same problem and THE ONE OF SOLUTION IS to

Use [ScriptIgnore] atribute .. it will solve the problem.

add system.web.extensions reference and add namespace:

Using System.Web.Script.Serialization.

If you still have questions..Read on..for some detailed explanation..

i have a User class with..

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using Iesi.Collections.Generic;

using System.Runtime.Serialization;

namespace RAPortal.Core.Entities

{

public class User

{

   private int _userId;

   private string _firstName;

   private string _lastName;

private IList _applications;

   private IList<Group> _groups;

   private IList<ApplicationRequest> _applicationRequests;

....Properties..

   public virtual int UserId

   {

       get

       {

           return _userId;

       }

       set

       {

           _userId = value;

       }

   }

   public virtual string Title

   {

       get

       {

           return _title;

       }

       set

       {

           _title = !String.IsNullOrEmpty(value) ? value.ToUpper().Trim() : null;

       }

   }

public virtual IList Groups

   {

       get

       {

           return _groups;

       }

       set

       {

           _groups = value;

       }

   }

   public virtual IList<UserPrivilege> UserPrivileges

   {

       get

       {

           return _userPrivileges;

       }

       set

       {

           _userPrivileges = value;

       }

   }

   public virtual IList<UserRole> UserRoles

   {

       get

       {

           return _userRoles;

       }

       set

       {

           _userRoles = value;

       }

   }

...so on...

and I have Groups class..

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Script.Serialization;

using System.Runtime.Serialization;

namespace RAPortal.Core.Entities

{

public class Group

{

   private int _groupId;

   private string _name;

   private IList<User> _users;

   public virtual int GroupId

   {

       get

       {

           return _groupId;

       }

       set

       {

           _groupId = value;

       }

   }

   public virtual string Name

   {

       get

       {

           return _name;

       }

       set

       {

           _name = !String.IsNullOrEmpty(value) ? value.ToUpper().Trim() : null;

       }

   }

   [ScriptIgnore]

   public virtual IList<User> Users

   {

       get

       {

           return _users;

       }

       set

       {

           _users = value;

       }

   }

}

}

Since User is referenced in the groups.. the json think that it is Circular reference and It will throw an exception..so the fix is to add [ScriptIgnore] on top of the User. And add the reference and namespace to this class like it..

It solved my problem .. I am sure there are better ways out there !!! Cheers...

And remember you should add [scriptIgnore] only in the groups class and not in the Users class..

kalyan
Your example is a little bit too long to clearly illustrate your point.
Richard
A: 

In my experience, the JavaScriptSerializer respects some of the XmlSerialization attributes such as XmlIgnore too.

Jeremy Bell
+2  A: 

You may use the [ScriptIgnore] attribute (in System.Web.Extensions). See http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx for an example.

JacobE
Ace, exactly what I was looking for.
Richard