Search code examples
c#apiodatamicrosoft.aspnetcore.odata

Not getting OData response when API returns a derived entity not having a key of its own


I have a controller class like this

public class OwnerController : ODataController
{
  [EnableQuery(MaxAnyAllExpressionDepth = 5)]
  public async Task<OwnersResponse> Get(string fileId, string token)
  {
    var response = await this._service.ListOwnersAsync(token, fileId).ConfigureAwait(false);
    return response;
  }
}

and these are my Model classes

public class OwnersResponse : CollectionResponseOfT<Owner>
{
}
public class CollectionResponseOfT<T>
{
  [JsonProperty("items")]
  [Key]
  public IEnumerable<T> Items { get; set; }

  [JsonProperty("offset", NullValueHandling=NullValueHandling.Ignore)]
  public int? Offset { get; set; }
}

and

public class Owner
{
  [JsonProperty("index", NullValueHandling = NullValueHandling.Ignore)]
  [Key]
  public int Index { get; set; }

  [JsonProperty("personId", NullValueHandling = NullValueHandling.Ignore)]
  public string PersonId { get; set; }
}

and this is my ModelBuilder class

public static IEdmModel GetEdmModel()
{
  var builder = new ODataConventionModelBuilder();  
  builder.EntitySet<Owner>("Owner");
  //builder.EntitySet<OwnersResponse>("OwnersResponse"); --> cannot set this as there is no key
  return builder.GetEdmModel();
}

Basically how do I make this API work with OData? when I call something like this http://localhost:5000/odata/Owner, I get a normal response and not something like the below with odata context.

{
    "@odata.context":.....
}

OData works if the API directly returns

public async Task<Owner> Get(string fileId, string token)
{
  var response = await this._service.GetOwnersAsync(token, fileId).ConfigureAwait(false);
  return response;
}

Solution

  • By adding the below to the ModeBuilder.getEdmModel() it worked for me.

    builder.EntitySet<CollectionResponseOfT<Owner>>("Owner").EntityType.HasKey(t => new {t.Offset});
    

    and I can query http://localhost:5000/odata/Owner?$expand=Items($filter=contains(PersonId, 'e'))

    and get Response like below

    {
    "@odata.context": ...
    }