Search code examples
c#asp.net-web-apicode-first

Attempted Serialization Of ICollection even with IgnoreDataMember and JsonIgnore


I am having some issues avoiding serialization of certain ICollection properties in Web Api. It seems the common suggestion to avoiding serialization is to add IgnoreDataMember or JsonIgnore. I don't want to serialize the one-to-many and one-to-one properties.

I have the following model:

public class Player
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key, Column(Order=0)]
    public Guid PlayerId { get; set; }

    [IgnoreDataMember]
    public virtual ICollection<Player> Friends { get; set; }

    [IgnoreDataMember]
    [Required]
    public string Password { get; set; }

    [MaxLength(100)]
    [Index(IsUnique = true)]
    public string Username { get; set; }

    [IgnoreDataMember]
    public virtual ICollection<WordChallenge> IssuedChallenges { get; set; }

    [IgnoreDataMember]
    public virtual ICollection<WordChallenge> ReceivedChallenges { get; set; }
}

However when I do a POST to the endpoint I'm getting the following exception:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

In this case it should only be attempting to serialize PlayerId and Username

Since it was requested, the following manages the dbContext:

public async Task<IEnumerable<Player>> GetFriends(Guid playerId)
{
    //Handles common exceptions and manages the dbcontext. In this case context is disposed off after the interaction is done.
    return await DbInteraction(
        async dbModel =>
        {
            var player = await GetPlayerById(playerId, dbModel);
            return player.Friends.ToList();
        });
}

Controller:

// GET: api/Friend/5
public async Task<ReturnObject<IEnumerable<Player>>> Get(Guid token, Guid id)
{
    var playerService = new PlayerService(base._wordModelFactory);
    var fields = await playerService.GetFriends(id);

    return ReturnData(fields);
}

Solution

  • Instead of marking members you don't want to be serialized with IgnoreDataMember, in your case (and in general) it's better to mark class with DataContact and mark members you want to be serialized with DataMember.

    Still you might wonder why you observe such behavior with IgnoreDataMember and navigation properties. My guess would be - to support lazy loading when you access navigation property, EF might create dynamic proxy class for your POCO class. Note that your navigation properties are marked with "virtual". That is for EF to be able to override them in that dynamic proxy class and add lazy loading behavior. IgnoreDataMember attribute is not inherited, and so in that inherited proxy class navigation properties are not longer marked with it, and so serializer will try to include them.