Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid OData control annotations for expanded navigation property #2273

Closed
korygin opened this issue Dec 8, 2021 · 1 comment · Fixed by OData/AspNetCoreOData#1088
Closed
Assignees

Comments

@korygin
Copy link

korygin commented Dec 8, 2021

Invalid OData control annotations such as @odata.context, @odata.id, @odata.editLink, etc. are rendered for an expanded non-contained 1->1 navigation property that is bound to a contained entity set.

Assemblies affected

OData .Net lib 7.9.4

Reproduce steps

Sample metadata:

<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
  <edmx:DataServices>
    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Core">
      <EntityType Name="EntityBase" Abstract="true" OpenType="true">
        <Key>
          <PropertyRef Name="Id"/>
        </Key>
        <Property Name="Id" Type="Edm.Int32" Nullable="false"/>
        <Property Name="Name" Type="Edm.String" Nullable="false"/>
      </EntityType>
      <EntityType Name="Site" BaseType="Core.EntityBase" OpenType="true">
        <NavigationProperty Name="Plants" Type="Collection(Core.Plant)" ContainsTarget="true"/>
      </EntityType>
      <EntityType Name="Plant" BaseType="Core.EntityBase" OpenType="true">
        <NavigationProperty Name="Site" Type="Core.Site" Nullable="false"/>
        <NavigationProperty Name="Pipelines" Type="Collection(Core.PipelineBase)" ContainsTarget="true"/>
      </EntityType>
      <EntityType Name="PipelineBase" BaseType="Core.EntityBase" Abstract="true" OpenType="true">
        <NavigationProperty Name="Plant" Type="Core.Plant" Nullable="false"/>
      </EntityType>
      <EntityContainer Name="ODataService">
        <EntitySet Name="Sites" EntityType="Core.Site">
          <NavigationPropertyBinding Path="Plants/Pipelines/Plant" Target="Sites/Plants"/>
          <NavigationPropertyBinding Path="Plants/Site" Target="Sites"/>
        </EntitySet>
      </EntityContainer>
    </Schema>
    <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Plant1">
      <EntityType Name="Pipeline" BaseType="Core.PipelineBase" OpenType="true">
        <Property Name="Length" Type="Edm.Int32"/>
      </EntityType>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

The following OData request https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)?$expand=Plant&$format=application/json;odata.metadata=full will produce the invalid response. Note that even though there is no @odata.context annotation for the expanded Plant property in the sample below, we have instances when it gets generated incorrectly and breaks OData clients. The sample project that demoes this problem is attached.

Expected result

The OData serializer should use navigation property bindings of the root entity set when generating OData control annotation links. The expected output would be:

{
  "@odata.context": "https://localhost:44113/api/v1/$metadata#Sites(1)/Plants(1)/Pipelines/Plant1.Pipeline(Plant())/$entity",
  "@odata.type": "#Plant1.Pipeline",
  "@odata.id": "Sites(1)/Plants(1)/Pipelines(1)",
  "@odata.editLink": "Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline",
  "Id": 1,
  "Name": "Pipeline 1",
  "Length": 300,
  "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline/Plant/$ref",
  "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline/Plant",
  "Plant": {
    "@odata.type": "#Core.Plant",
    "@odata.id": "Sites(1)/Plants(1)",
    "@odata.editLink": "Sites(1)/Plants(1)",
    "Id": 1,
    "Name": "Plant 1",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Site/$ref",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines/$ref",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines"
  }
}

Actual result

{
  "@odata.context": "https://localhost:44113/api/v1/$metadata#Sites(1)/Plants(1)/Pipelines/Plant1.Pipeline(Plant())/$entity",
  "@odata.type": "#Plant1.Pipeline",
  "@odata.id": "Sites(1)/Plants(1)/Pipelines(1)",
  "@odata.editLink": "Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline",
  "Id": 1,
  "Name": "Pipeline 1",
  "Length": 300,
  "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline/Plant/$ref",
  "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plant1.Pipeline/Plant",
  "Plant": {
    "@odata.type": "#Core.Plant",
    "@odata.id": "Sites(1)/Plants(1)/Pipelines(1)/Plants(1)",
    "@odata.editLink": "Sites(1)/Plants(1)/Pipelines(1)/Plants(1)",
    "Id": 1,
    "Name": "Plant 1",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plants(1)/Site/$ref",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plants(1)/Site",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plants(1)/Pipelines/$ref",
    "[email protected]": "https://localhost:44113/api/v1/Sites(1)/Plants(1)/Pipelines(1)/Plants(1)/Pipelines"
  }
}

Note that there is no Plants navigation property defined on the pipeline entity thus links are invalid.

ODataService.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants