Serializing EF4.1 Objects Using JSON.Net

I am building an application using MVC3, the Razor viewer, the unit of work repository template, and using the EF4.1 Code First to define my data model.

Here's a little background (look at it if you want).

The application itself is an Intranet only.

The two main objects are MenuItem and Department, of which:

  • MenuItem can have many branches
  • Departments can have many MenuItems
  • MenuItem can have MenuItem as parent

This is how I defined my objects

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 FluentAPI to define Self Reference Many-to-Many for MenuItem.

The problem I am facing is passing the MenuItem element to the view via JSON. The central issues are that I have a circular link between my objects that the built-in JSON parser cannot handle, and I have lazy loading and creating a proxy that are still on.

I am using the Nuget JSON.net library as my JSON Serializer, as this seems to be a good way to get round reference. Now I'm not sure how to “fix” the problem of proxy generation. The serializer is currently throwing 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. 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'm going to have some fun loading all the MenuItem children, so I am getting away from this. I read quite a lot and there seem to be a lot of different answers, including projecting objects onto another object and serializing this, etc. Etc. Ideally, some way to configure JSON.net to ignore the RelationshipManager?

Update

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

 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 that is implemented by all the entity objects of my First code.

+6
source share
2 answers

Well, you used the powerful serialization API, which also serializes links of all participants, and now you complain that it serializes all participants :)

I have not tested it, but I believe that this will bring you closer to the solution.

JSON.NET is a pretty powerful tool, and it should offer you the option of expanding to avoid this behavior, but you will have to code it yourself. You will need a custom DataContractResolver where you determine which members should be serialized. Here is a similar example for NHibernate.

You can implement some logic that will only accept members present in the dynamic proxy parent class. Hope this does not break the lazy load. To verify that the current object is a proxy, you can use this code to get all known proxy types:

 IEnumerable<Type> types = ((IObjectContextAdapter)dbContext).ObjectContext.GetKnownProxyTypes(); 
0
source

I understand that this question has an accepted answer, but I thought that I would send my EF Code First solution to future viewers. I managed to get around the error message using the contract recognizer 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 the EF Code First classes inherit from the POCO class that you really want to serialize, so if we can determine when we look at the generated EF class (by checking the namespace), we can simply serialize using the properties from the base class and therefore, only serialize the POCO properties that we actually performed in the first place.

+2
source

Source: https://habr.com/ru/post/894607/


All Articles