Entity ForEach [JsonIgnore]

.net-core c# entity-framework-core

Question

I have maybe 60-70 classes that all have various Id columns that I would like to exclude when I return JSON data from the Web API. Internally I join on Id, but anything front-facing uses a Guid. So my primary key is the Id (int) and then there is a Guid there for the outside world to use to make things more secure.

Typically you just add [JsonIgnore] over the property and it takes care of it, but I have a lot of classes that may get updated from time to time. Whenever I scaffold everything and force an overwrite, it's going to remove my changes.

Instead of manually adding [JsonIgnore] to every Id column I want to exclude, it seems more logical to just handle this in OnModelCreating. I am able to loop through properties and use .Ignore, but that removes the property from everything else as well. I just don't want it to serialize and return any of the columns named "Id" and any foreign keys (which are also Ids).

So here is an example from one class

[JsonIgnore]
public int Id { get; set; }
public Guid Guid { get; set; }
public string Name { get; set; }
public bool? Active { get; set; }

[JsonIgnore]
public int HoldTypeId { get; set; }
public DateTime CreateDateTime { get; set; }
public DateTime UpdateDateTime { get; set; }

I can "make it work" the hard way, but I'm hoping there is a quick and easy way to achieve the same results so I can spend time on the important pieces.

EDIT: Here is what is returning the data to the user.

// GET: api/Distributors
[HttpGet]
public async Task<ActionResult<IEnumerable<Distributor>>> GetDistributor()
{
    return await _context.Distributor.ToListAsync();
}
1
2
1/26/2019 8:35:53 PM

Accepted Answer

You could write your own DefaultContractResolver to exclude any property that you want on serialization process.

Below there is an example for it:

public class PropertyIgnoringContractResolver : DefaultContractResolver
    {
        private readonly Dictionary<Type, string[]> _ignoredPropertiesContainer = new Dictionary<Type, string[]>
        {
            // for type student, we would like to ignore Id and SchooldId properties.
            { typeof(Student), new string[] { "Id", "SchoolId" } }
        };

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
            string[] ignoredPropertiesOfType;
            if (this._ignoredPropertiesContainer.TryGetValue(member.DeclaringType, out ignoredPropertiesOfType))
            {
                if (ignoredPropertiesOfType.Contains(member.Name))
                {
                    property.ShouldSerialize = instance => false;
                    // Also you could add ShouldDeserialize here as well if you want.
                    return property;
                }
            }

            return property;
        }
    }

then you should configure this in your Startup.cs in ConfigureServices like below

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
                .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new PropertyIgnoringContractResolver());
        }

However what i actually would do is that i would create response DTO's to match the needs of my API responses. Instead of returning raw entity types. Like;

[HttpGet]
public async Task<ActionResult<IEnumerable<Distributor>>> GetDistributor()
{
   return await _context.Distributor.Select(dist => new DistributorDTO 
   {
     Name = dist.Name,
     // so on..
   }).ToListAsync();
}

By implementing something like this, you would also optimize your database queries as well by only selecting the properties that the API response requires.

2
1/26/2019 8:47:02 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow