Search code examples
odatawcf-data-servicesasp.net-web-apiastoriawcf-data-services-client

Proper way to call nested Expand() from .NET OData 4 Client


Problem

In an OData 4 service on Web API, what is the proper way to call nested $expand from a .NET client? We are using the OData Client Generator. Back in the prior WCF Data Services with OData 3 service we could call .Expand("Customers/Orders"). In Web API with OData 4 we can no longer do so and receive the following should you attempt .Expand("Customers/Orders"):

The query specified in the URI is not valid. Found a path traversing multiple navigation >properties. Please rephrase the query such that each expand path contains only type >segments and navigation properties.

Workaround

We are able to work around this by calling expand like so: .Expand("Customers($expand=Orders)"). In non-nested $expand scenarios, I like the lambda support like so .Expand(d => d.Customers). Is there a proper way in .NET OData 4 client to call nested expands without the unfortunate magic string of .Expand("Customers($expand=Orders)")? If not, is there a cleaner string pattern like "Customers/Orders" that would work? Thanks.


Solution

  • In OData v4, it is not valid to expand multi levels, such as what you mentioned in the question: .Expand("Customers/Orders"). I dont think the client will support such API. Here is what in the ABNF http://docs.oasis-open.org/odata/odata/v4.0/os/abnf/odata-abnf-construction-rules.txt:

    expand            = '$expand' EQ expandItem *( COMMA expandItem )
    expandItem        = STAR [ ref / OPEN levels CLOSE ]
                      / expandPath
                        [ ref   [ OPEN expandRefOption   *( SEMI expandRefOption   ) CLOSE ]
                        / count [ OPEN expandCountOption *( SEMI expandCountOption ) CLOSE ]
                        /         OPEN expandOption      *( SEMI expandOption      ) CLOSE 
                        ]
    expandPath        = [ qualifiedEntityTypeName "/" ] 
                        *( ( complexProperty / complexColProperty ) "/" [ qualifiedComplexTypeName "/" ] )
                        navigationProperty 
                        [ "/" qualifiedEntityTypeName ]