Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing EF4.1 Entities using JSON.Net

I am building an application using MVC3, Razor view engine, Repository Pattern with Unit of Work and using EF4.1 Code First to define my data model.

Here is a bit of background (gloss over it if you want).

The application itself is just an Intranet 'Menu'.

The 2 main entities are MenuItem and Department of which:

  • MenuItem can have many Departments
  • Departments can have many MenuItems
  • MenuItem may have a MenuItem as a parent

This is how I have defined my Entities

public class MenuItem
{
   public int MenuItemId { get; set; }
   public string Name { get; set; }
   public string Url { get; set; }
   public virtual ICollection<Department> Departments { get; set; }
   public int? ParentId { get; set; }
   public virtual MenuItem ParentMenuItem { get; set; }
}

public class Department
{
   public int DepartmentId { get; set; }
   public string Name { get; set; }
   public virtual ICollection<MenuItem> MenuItems { get; set; }
}

I am using the FluentAPI to define the Self Reference Many-to-Many for the MenuItem.

The issue I am having is passing a MenuItem to the view via JSON. The central issues are that I have a circular reference between my entities that the built in JSON parser can't deal with and I have lazy loading and proxy generation still enabled.

I am using JSON.net library from Nuget as my JSON Serializer as this seems to be a nice way round the circular reference issue. I now am unsure how to 'fix' the proxy generation issue. Currently the serializer throws The RelationshipManager object could not be serialized. This type of object cannot be serialized when the RelationshipManager belongs to an entity object that does not implement IEntityWithRelationships.

Can anyone help me with this? If I turn off proxy generation, I am going to have a hell of a time loading all of the MenuItem children so I am keen leave this on. I have read a fair amount and there seems to be a variety of different answers including projecting the entities into another object and serialize that, etc, etc. Ideally there would be some way of configuring JSON.net to ignore the RelationshipManager object?

Update

Here is what I have used as a Custom ContractResolver for JSON.Net serializer. This seems to have sorted out my issue.

public class ContractResolver : DefaultContractResolver
{
    private static readonly IEnumerable<Type> Types = GetEntityTypes();
    private static IEnumerable<Type> GetEntityTypes()
    {
        var assembly = Assembly.GetAssembly(typeof (IEntity));
        var types = assembly.GetTypes().Where(t => String.Equals(t.Namespace, "Namespace", StringComparison.Ordinal));
        return types;
    }

    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        if (!AllowType(objectType))
            return new List<MemberInfo>();

        var members = base.GetSerializableMembers(objectType);
        members.RemoveAll(memberInfo => (IsMemberEntityWrapper(memberInfo)));
        return members;
    }

    private static bool AllowType(Type objectType)
    {
        return Types.Contains(objectType) || Types.Contains(objectType.BaseType);
    }

    private static bool IsMemberEntityWrapper(MemberInfo memberInfo)
    {
        return memberInfo.Name == "_entityWrapper";
    }
}

IEntity is an interface all my Code First entity objects implement.

like image 989
Matt Demler Avatar asked Aug 09 '11 05:08

Matt Demler


People also ask

What is serializing in JSON?

Json namespace provides functionality for serializing to and deserializing from JavaScript Object Notation (JSON). Serialization is the process of converting the state of an object, that is, the values of its properties, into a form that can be stored or transmitted.

How do you serialize and deserialize an object in C# using JSON?

It returns JSON data in string format. In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it calls the static method DeserializeObject() of the JsonConvert class by passing JSON data.

Which library is used by Web API for serializing JSON?

By default, JsonMediaTypeFormatter uses the Json.NET library to perform serialization. Json.NET is a third-party open source project.

How do I deserialize a JSON string to an object in C#?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.


1 Answers

I realise this question has an accepted answer, but I thought I would post my EF Code First solution for future viewers. I was able to get around the error message with the contract resolver below:

 class ContractResolver : DefaultContractResolver
 {
      protected override List<System.Reflection.MemberInfo> GetSerializableMembers(Type objectType)
      {
           if (objectType.Namespace.StartsWith("System.Data.Entity.Dynamic"))
           {
                return base.GetSerializableMembers(objectType.BaseType);
           }

           return base.GetSerializableMembers(objectType);
      }
 }

This works because EF Code First classes inherit from the POCO class that you actually want serialized, so if we can identify when we are looking at an EF generated class (by checking the namespace) we are able to just serialize using the properties from the base class, and therefore only serialize the POCO properties that we were really after in the first place.

like image 194
Steve Greatrex Avatar answered Oct 02 '22 09:10

Steve Greatrex