OData / OData/AspNetCoreOData

[FromBody] Deserialization fails on ODataController when Body contains [NotMapped] property

Open
#91 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
505
Forks
186
PR merge metrics
No merged PRs in 30d

Description

I am having issues with deserialization on my OData controller when using [FromBody] attribute when the body contains a property that doesn't exist in the model, such as an [NotMapped] property. Is there a way to tell the InputFormatter to ignore properties that don't exist in the model, instead of failing to bind the model giving me a null model? Here is an example model:

`public class Person
{
public Person() { }

  [Key]
  public int Id { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }

  [NotMapped]
  public string FullName => FirstName + " " + LastName;

}`

Note the [NotMapped] property FullName. I don't want this in my database, since it is just a simple calculated field, but I still want it to be serialized and deserialized in my ODataControllers. In order to have it serialized, I added the following to my GetEDMModel() function.

builder.StructuralTypes.First(t => t.ClrType == typeof(Attorney)).AddProperty(typeof(Person).GetProperty("FullName"));

This serializes the FullName property in the GET methods of my Person ODataController.
I have a React Client which receives this Person and manipulates it as necessary, and then makes a PUT request to the Person ODataController to update the Person. The body of the PUT request includes the [NotMapped] FullName property which does not have setter in the model.

Example body:

{ "@odata.context": "https://localhost:44304/rest/$metadata#Persons/$entity", "Id": 1, "FirstName": "Jimmy", "LastName": "Johnson", "FullName": "Jimmy Johnson", }

The expected behavior (in my opinion) should be that the InputFormatter ignores the FullName property, since it is [NotMapped]in the model. Instead, theInputFormatterfails to bind the model, and thePerson` entity is null once inside my contoller.

`[ODataRoute("{id}")]
public async Task Put([FromODataUri] int id, [FromBody] Person person)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
if (id != person.Id) return BadRequest();

    db.Entry(person).State = EntityState.Modified;
    await db.SaveChangesAsync();
    return Updated(person);
}`

How do I get the inputformatter to deserialize an entity, even if the body includes a [NotMapped] property?

As a temporary work around, I am removing the [NotMapped] property on the client before the PUT request, but ideally this would be handled when deserializing.

I noticed the @odata.context property is automatically ignored, and does not cause deserialization to fail. Maybe there is a way to denote [NotMapped] to be ignored in a similar way?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the OData InputFormatter path used by the [FromBody] Person parameter in Put, and review the custom GetEDMModel configuration that adds FullName. Reproduce the PUT request containing FullName and compare its handling with @odata.context. Done means the entity binds successfully, FullName is ignored for persistence, and ModelState remains valid.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.