Nathan Friend
Nathan Friend

Reputation: 12814

POST-ing a new entity to a Web.API OData endpoint without an ID

I'm building a proof-of-concept API using ASP.NET Core 2.1, Web.API, and OData (7.0.0-beta4).

One of my OData endpoints is responsible for basic CRUD operations on an Employer entity. The POST endpoint - which creates a brand new Employer record - is defined like this:

// POST: api/Employers
[HttpPost]
public async Task<IActionResult> PostEmployer([FromBody] Employer employer)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    _context.Employers.Add(employer);
    await _context.SaveChangesAsync();

    return CreatedAtAction("GetEmployer", new { id = employer.Id }, employer);
}

My Employer entity is defined like this:

namespace MyProject.Models
{
    public class Employer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public bool IsActive { get; set; }
    }
}

If I hit this OData endpoint with a POST body like this:

{
    "Name": "My Employer",
    "IsActive": true
}

I get an error message:

InvalidOperationException: No route matches the supplied values.

This is because the Id property is required, but is not provided in my JSON. However, I don't want to provide the Id property, because this property will be auto-generated by the database. If I do provide the Id property, my request is successfully routed, but I get an Entity Framework error later in the process (Cannot insert explicit value for identity column), which makes sense.

How can I make my OData endpoint ignore the required Id property during a POST request?

Upvotes: 1

Views: 1046

Answers (2)

Nathan Friend
Nathan Friend

Reputation: 12814

Figured it out - it turns out the issue had nothing to do with the Id property in my entity class. Instead, the problem was this line:

return CreatedAtAction("GetEmployer", new { id = employer.Id }, employer);

The framework must do some kind of validation on the specified action ("GetEmployer"), and it was throwing an error that this action is invalid.

I'm not sure how to correct this string value, but I can avoid the issue altogether by using a simpler return value:

return Ok(new { Id = employer.Id });

Upvotes: 1

alec
alec

Reputation: 396

Try adding the [DataContract] and [DataMember] attributes to your Employer model:

[DataContract]
public class Employer
{
    [DataMember(Name = "Id", IsRequired=false, EmitDefaultValue=false)]
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsActive { get; set; }
}

More info on DataMemberAttribute properties: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute_properties(v=vs.110).aspx

Upvotes: 1

Related Questions