Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.net WebApi OData V4 problems with nested $expands

I have a OData V4 over Asp.net WebApi (OWIN).

Everything works great, except when I try to query a 4-level $expand.

My query looks like:

http://domain/entity1($expand=entity2($expand=entity3($expand=entity4)))

I don't get any error, but the last expand isn't projected in my response.

More info:

  1. I've set the MaxExpandDepth to 10.
  2. All my Entities are EntitySets.
  3. I'm using the ODataConventionModelBuilder.
  4. I've opened an SQL-profiler and could see that the query (and the result) is correct. It's some filter that occurs after the query is executed.
  5. I've searched the web and didn't find anything suitable.
  6. I've tried different entity 4 level $expands and they didn't work as well.

Edit:

I've overridden the OnActionExecuted:

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    base.OnActionExecuted(actionExecutedContext);

    var objectContent = actionExecutedContext.Response.Content as ObjectContent;
    var val = objectContent.Value;

    var t = Type.GetType("System.Web.OData.Query.Expressions.SelectExpandWrapperConverter, System.Web.OData");
    var jc = Activator.CreateInstance(t) as JsonConverter;
    var jss = new JsonSerializerSettings();
    jss.Converters.Add(jc);

    var ser = JsonConvert.SerializeObject(val, jss);
 }

The serialized value contains entity4.

I still have no idea what component removes entity4 in the pipe.

Edit #2:

I've create an adapter over DefaultODataSerializerProvider and over all the other ODataEdmTypeSerializer's. I see that during the process the $expand for entity4 exists and when the ODataResourceSerializer.CreateNavigationLink method is called on that navigationProperty (entity4) then it returns null.

I've jumped into the source code and I could see that the SerializerContext.Items doesn't include the entity4 inside it's items and the SerializerContext.NavigationSource is null.

To be specific with versions, I'm using System.Web.OData, Version=6.1.0.10907.

like image 728
Amir Popovich Avatar asked Jun 20 '18 07:06

Amir Popovich


1 Answers

Ok, so I noticed the problem was due to the fact that my navigation property was of type EdmUnknownEntitySet and the navigation property lookup returns null (source code attached with an evil TODO..):

/// <summary>
/// Finds the entity set that a navigation property targets.
/// </summary>
/// <param name="property">The navigation property.</param>
/// <returns>The entity set that the navigation propertion targets, or null if no such entity set exists.</returns>
/// TODO: change null logic to using UnknownEntitySet
public override IEdmNavigationSource FindNavigationTarget(IEdmNavigationProperty property)
{
    return null;
}

So I understood my problem was with the EdmUnknownEntitySet.

I digged into the code and saw that I needed to add the ContainedAttribute to the my navigation properties.

Since my solution is kind of a Generic repository, I've added it in the Startup for All navigation properties:

builder.OnModelCreating = mb => mb.StructuralTypes.SelectMany(s => s.NavigationProperties
            .Where(np => np.Multiplicity == EdmMultiplicity.Many)).Distinct().ForEach(np => np.Contained());

//......

var model = builder.GetEdmModel();
like image 58
Amir Popovich Avatar answered Nov 11 '22 19:11

Amir Popovich