2

I have read a lot of previous solutions for this problem but none worked for me.

I have a circular relation between Event and User object:

public class Event : EntityData
{
    [Required]
    [ForeignKey("Creator")]
    public string CreatorId { get; set; }
    public User Creator { get; set; }

    [InverseProperty("ParticipantIn")]
    public virtual ICollection<User> Participants { get; set; }

    [InverseProperty("ManagerIn")]
    public virtual ICollection<User> Managers { get; set; }
}

As you can see I have three references to User from this class: event creator, list of managers, and list of participants.

The user class contains references to Event as well:

public class User: EntityData
{
    [InverseProperty("Participants")]
    public virtual ICollection<Event> ParticipantIn { get; set; }

    [InverseProperty("Managers")]
    public virtual ICollection<Event> ManagerIn { get; set; }
}

Now, the issue is that when I try to serialize an event, like in my createEvent function, it tells me that there is a self referencing loop, that is because when the event is created, I am adding it to the creator's 'ManagerIn' Collection.

That line causes Event->Creator->ManagerIn->Event->Creator->..... LOOP

I tried anything, I also had a version of this code with public virtual User Creator, in order to make it load lazily..

For now, my solution is very not elegant, before returning the event to the client I am performing:

event.Creator = null;

and

event.Managers = null;

in order to avoid a self referencing loop.

What is the right way to solve this kind of problem?

Thanks in advance, Liran!

Liran Revivo
  • 1,143
  • 3
  • 15
  • 20
  • What do you use to serialize it? – Evk Mar 15 '17 at 12:46
  • 1
    If you're using XML http://stackoverflow.com/questions/5004397/is-it-possible-to-perform-serialization-with-circular-references may be relevant – Chris Mar 15 '17 at 12:48
  • 1
    http://stackoverflow.com/questions/26434738/how-do-you-really-serialize-circular-referencing-objects-with-newtonsoft-json may be of interest for json – Chris Mar 15 '17 at 12:49
  • Possible duplicate of [How Do You "Really" Serialize Circular Referencing Objects With Newtonsoft.Json?](http://stackoverflow.com/questions/26434738/how-do-you-really-serialize-circular-referencing-objects-with-newtonsoft-json) – Igor Mar 15 '17 at 12:50
  • There may be others too. Its definitely useful to show us your serialization code and a minimal complete example of your issue (ie give us a program that creates those objects with circular references and then serializes them with whatever method you are using so we can a) see exactly what you are doing and how your error is generated and b) easily modify your code to make it work rather than having to write it all ourselves to confirm any solutions we suggest. – Chris Mar 15 '17 at 12:51
  • @Chris I am not serializing those myself. I just return the object in the MobileAppController and the serialization happens automatically. – Liran Revivo Mar 15 '17 at 13:49
  • @LiranRevivo: you may not be writing the serialization code yourself but you are doing something to cause it to be serialised such as calling a method in your controller. For example are you calling the `Json` Method on the controller to tell it to convert your object to json? – Chris Mar 15 '17 at 13:59
  • No no! I really meant it, I was surprised as well at the beginning, but that's how it's work in the azure mobile applications I guess, all I am doing is implementing a function, like : [HttpPost, Route("api/User/CreateUser")] public async Task< CreateUser([FromBody] JObject item), and all I do at the end is 'return user' and the serialization happens like a charm when there is no self referencing loop. – Liran Revivo Mar 15 '17 at 14:15
  • @LiranRevivo - the act of just returning something is still serialization as something in the pipeline will serialize the response if it is not done directly by the code you are calling. The pipeline will still depend on some serializer implementation like json.net. – Igor Mar 15 '17 at 18:00
  • @Igor Of course there is a serialization somewhere along the chain. But since I didn't implemented it I really do not know how it works. – Liran Revivo Mar 16 '17 at 15:07
  • You might have a look at my answer on **[“Self Referencing Loop Detected” exception with JSON.Net](https://stackoverflow.com/questions/40472419/self-referencing-loop-detected-exception-with-json-net/51235783#51235783)** page. – Murat Yıldız Jul 08 '18 at 20:41

2 Answers2

0

I read this is one way to do so.

MyContextEntities.ContextOptions.ProxyCreationEnabled = false;

Otherwise, I would suggest serializing to a different object and avoid serializing your poco's.

0

Because you are specifying the collections as virtual, Entity Framework is Lazy Loading the related entities which is building objects with circular references which the WebAPI JSON serializer does not particularly work well with.

You can disable Lazy Loading for the particular query or queries using

MyEntities.Configuration.LazyLoadingEnabled = false;

Or if you wanted to, remove the virtual keyword from the property declaration. With either of these options, you can then eager load the related collection if required using the Include extension method like so:

MyEntities.Set<Users>()
  .Include(u => u.ManagerIn)
  .Include("ParticipantIn");

(above shows both options for using Include to Eager Load)

The Load method can also be used to explicitly load related entities. Here is a Stack Overflow on Include vs. Load

I've also done something similar to what you have specified for setting the related entity collection to null to prevent that from being included in serialization. For that I'd recommend mapping your POCO / entity to a DTO (data transfer object) first so you can set up something repeatable and avoid accidentally calling SaveChanges() on the same context and unintentionally removing the relationship between your entities in SQL. Automapper is an existing solution that can do this mapping to a DTO or you can write your own Mapper utility class to give yourself a little bit more control.

The last potential option (that I'm aware of) is to adjust the HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandinging settings to ignore reference handling for everything / arrays / objects.

It really depends on your requirements and the rest of the code. Hopefully one of these leads you down the right path and good luck!

Community
  • 1
  • 1
Alex
  • 325
  • 1
  • 7
  • Hi man! Thanks for the specified answer. But whatever I do I'm still getting this error. let me give you an example. In my create event function I am performing var inserted = context.Events.Add(event); which adds the event, Then I am finding the User who created the event with var creator = await context.Users.FindAsync(new object[] { creatorId });, I do so in order to perform creator.ManagerIn.Add(created); so the event will be on his list. as soon as I am loading the creator object, the inserted object is now contain circular reference to the creator who have reference to the event etc... – Liran Revivo Mar 16 '17 at 15:05