AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

@odata.context url for navigation property

Open danleydmello opened this issue 2 years ago • 5 comments

The @odata.context url for the contained entity does not include the key of the entity-set.

e.g http://host/service/Orders(4711)/Item

Expected @odata.contex url in the response should be http://host/service/$metadata#Orders(4711)/Item/$entity

Actual @odata.contex url in the response is http://host/service/$metadata#Orders/Item/$entity //without key

Reference Odata specs http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_Entity

To reproduce the problem, run ODataDynamicModel Sample application Run this query http://localhost:4527/odata/mydatasource/Products/1/DetailInfo

In response the key 1 is missing: {"@odata.context":"http://localhost:4527/odata/mydatasource/$metadata#Products/ns.DetailInfo/$entity","ID":88,"Title":"abc_detailinfo"}

danleydmello avatar Sep 07 '22 20:09 danleydmello

Question: if you change your route to use parenthesis-based keys (i.e. http://localhost:4527/odata/mydatasource/Products(1)/DetailInfo) does this change the result in any way?

julealgon avatar Sep 08 '22 13:09 julealgon

Question: if you change your route to use parenthesis-based keys (i.e. http://localhost:4527/odata/mydatasource/Products(1)/DetailInfo) does this change the result in any way?

@julealgon , no, still same issue. To reproduce it, I added template for ({key}) in https://github.com/OData/AspNetCoreOData/blob/main/sample/ODataDynamicModel/Extensions/EntitySetWithKeyTemplateSegment.cs

Response I got: {"@odata.context":"http://localhost:4527/odata/mydatasource/$metadata#Products/ns.DetailInfo/$entity","ID":88,"Title":"abc_detailinfo"}

danleydmello avatar Sep 08 '22 14:09 danleydmello

Hi @ElizabethOkerio -- it looks like you're oncall this week. This does look like a bug, and I do think we have issues in this area. Can you work with @xuzhg (who is backup) to verify and figure out a fix.

mikepizzo avatar Sep 13 '22 16:09 mikepizzo

Hi All, i've been working with @danleydmello on this problem -- just wondering if there is any update as this is currently blocking us.

sfalik avatar Sep 29 '22 14:09 sfalik

@sfalik yes we have a fix. Hope to get it merged soon.

ElizabethOkerio avatar Sep 29 '22 15:09 ElizabethOkerio

@ElizabethOkerio, any update on this?

Thanks

danleydmello avatar Oct 25 '22 13:10 danleydmello

@sfalik @ElizabethOkerio, I would love to see an update here as well.

I found out that when you specify the full route template on the controller method, the context is set correctly, so it looks like a problem on the conventional routes.

dnperfors avatar Nov 29 '22 11:11 dnperfors

...I found out that when you specify the full route template on the controller method, the context is set correctly, so it looks like a problem on the conventional routes.

Thanks for the heads up!

@mikepizzo, @ElizabethOkerio any update here would really be appreciated!

sfalik avatar Nov 29 '22 13:11 sfalik

@sfalik @ElizabethOkerio, I would love to see an update here as well.

I found out that when you specify the full route template on the controller method, the context is set correctly, so it looks like a problem on the conventional routes.

After some more testing, this workaround doesn't fully work. In my case I had the contained item on a derived type and then the workaround worked, but on the main type, the workaround doesn't work!

@mikepizzo, @ElizabethOkerio any updates yet?

dnperfors avatar Dec 06 '22 09:12 dnperfors

@dnperfors will follow up on this work item this week. Will get back to you.

ElizabethOkerio avatar Dec 06 '22 10:12 ElizabethOkerio

@ElizabethOkerio , any update yet?

danleydmello avatar Jan 06 '23 18:01 danleydmello

@xuzhg

ElizabethOkerio avatar Jan 07 '23 13:01 ElizabethOkerio

@xuzhg and @ElizabethOkerio, I will not ask for an update, we probably won't get... Therefore I will just follow up on this. Because the @odata.context URL is not correctly generated, the (Microsoft) OData client can't handle the response. I don't have the exact error, but this is one of the blocking issues for using this library.

dnperfors avatar Feb 13 '23 09:02 dnperfors

@dnperfors , same problem we are facing, the PowerBI OData feed fails to handle the response in this situation

danleydmello avatar Feb 13 '23 13:02 danleydmello

@mikepizzo @ElizabethOkerio -- could we get an update on this please? This issue is still blocking us.

sfalik avatar Jun 05 '23 20:06 sfalik

This is one of the reasons we decided not to use this library at all. Of course there are multiple others, including the lack of documentation and communication.

dnperfors avatar Jun 05 '23 20:06 dnperfors

@sfalik @dnperfors Sorry this has taken some time to resolve. We've prioritized it and we are currently working on a solution for it. Thanks.

ElizabethOkerio avatar Jun 07 '23 19:06 ElizabethOkerio

Just a quick one: Looking at the csdl from the ODataDynamicModel,


<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="ns">
<EntityType Name="Product">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="Name" Type="Edm.String"/>
<Property Name="ID" Type="Edm.Int32"/>
<NavigationProperty Name="DetailInfo" Type="ns.DetailInfo" Nullable="false"/>
</EntityType>
<EntityType Name="DetailInfo">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Int32"/>
<Property Name="Title" Type="Edm.String"/>
</EntityType>
<EntityContainer Name="container">
<EntitySet Name="Products" EntityType="ns.Product">
<NavigationPropertyBinding Path="DetailInfo" Target="DetailInfos"/>
</EntitySet>
<EntitySet Name="DetailInfos" EntityType="ns.Product"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

DetailInfo is not a contained navigation property. If it were, it could have the ContainsTarget attribute set to True. Another thing I'm picking from the CSDL is that the entityset DetailInfos is assigned ns.Product entity type which it shouldn't. It should be assigned the ns.DetailInfos entity type.

We are still looking into this issue but the way this project has been set-up could be the cause of the issues with the context URL not being set appropriately.

ElizabethOkerio avatar Jun 12 '23 09:06 ElizabethOkerio

This is what have done to try and repro the issue.

Model classes:

 public class Account
    {
        public int AccountID { get; set; }
        public string Name { get; set; }
        [Contained]
        public IList<PaymentInstrument> PayinPIs { get; set; }
    }

    public class PaymentInstrument
    {
        public int PaymentInstrumentID { get; set; }
        public string FriendlyName { get; set; }
    }

Controller

        // GET ~/Accounts(100)/PayinPIs         
        [EnableQuery]
        public IActionResult GetPayinPIs(int key)
        {
            var payinPIs = _accounts.Single(a => a.AccountID == key).PayinPIs;
            return Ok(payinPIs);
        }

Request:

https://localhost:7098/odata/Accounts(100)/PayinPIs

Response:

{
    "@odata.context": "https://localhost:7098/odata/$metadata#Accounts(100)/PayinPIs",
    "value": [
        {
            "PaymentInstrumentID": 101,
            "FriendlyName": "101 first PI"
        },
        {
            "PaymentInstrumentID": 102,
            "FriendlyName": "102 second PI"
        }
    ]
}

ElizabethOkerio avatar Jun 12 '23 09:06 ElizabethOkerio

The response seems to be Ok. Could you please share your repro? Are you using a dynamic model?

ElizabethOkerio avatar Jun 12 '23 09:06 ElizabethOkerio

I see you are using a collection, the issue talks about a reference to a single type...

dnperfors avatar Jun 12 '23 09:06 dnperfors

@dnperfors I've updated my model to look like this:

    public class Account
    {
        public int AccountID { get; set; }
        public string Name { get; set; }

        [Contained]
        public PaymentInstrument PayinPI { get; set; }
    }

Controller

        // GET ~/Accounts(100)/PayinPI        
        [EnableQuery]
        public IActionResult GetPayinPI(int key)
        {
            var payinPIs = _accounts.Single(a => a.AccountID == key).PayinPI;
            return Ok(payinPIs);
        }

Request https://localhost:7098/odata/Accounts(100)/PayinPI

Response

{
    "@odata.context": "https://localhost:7098/odata/$metadata#Accounts(100)/PayinPI/$entity",
    "PaymentInstrumentID": 101,
    "FriendlyName": "101 first PI"
}

ElizabethOkerio avatar Jun 12 '23 09:06 ElizabethOkerio

The response seems to be Ok. Could you please share your repro? Are you using a dynamic model?

Thanks, @ElizabethOkerio for trying this out. Our code is in Azure DevOps repo so can't be shared easily,. Yes, we are using the dynamic model. We used ODataDynamicModel as an example to build our OData service.

You pointed out that there is an issue with the DetailInfo EDM in ODataDynamicModel. Have you tried fixing this issue and running ODataDynamicModel example to test if it produce the correct odata context url?

Thanks

danleydmello avatar Jun 12 '23 13:06 danleydmello

Yes looking into this.

ElizabethOkerio avatar Jun 15 '23 16:06 ElizabethOkerio

@danleydmello can you make updates as per this https://github.com/OData/AspNetCoreOData/pull/975 and let us know whether you get the right context URL.

ElizabethOkerio avatar Jul 03 '23 18:07 ElizabethOkerio

@ElizabethOkerio , Thanks for the update. I took your branch and ran the test using the ODataDynamicModel sample. Query: http://localhost:4527/odata/mydatasource/Products/1/DetailInfo Response: { "@odata.context": "http://localhost:4527/odata/mydatasource/$metadata#DetailInfos/$entity", "ID": 88, "Title": "abc_detailinfo" }

Maybe it is correct, but I am not sure. I was expecting something like this: { "@odata.context": "http://localhost:4527/odata/mydatasource/$metadata#Products(1)/DetailInfos/$entity", "ID": 88, "Title": "abc_detailinfo" }

I am using the OData specs reference to validate the response for this query: http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_Entity

Thanks

danleydmello avatar Jul 05 '23 22:07 danleydmello

@danleydmello DetailInfo is not a contained navigation property..I added another property ContainedDetailInfo that is contained.. If you run this:

http://localhost:4527/odata/mydatasource/Products/1/ContainedDetailInfo

This will return this:


{
"@odata.context": "http://localhost:4527/odata/mydatasource/$metadata#Products(1)/ContainedDetailInfo/$entity",
"ID": 88,
"Title": "abc_containeddetailinfo"
}

ElizabethOkerio avatar Jul 06 '23 06:07 ElizabethOkerio

Ok, it works for containment navigation property, But what about simple navigation property with navigationproprtybinding e.g DetailInfo? Its not clear from OData specs whats the context url should be.

danleydmello avatar Jul 07 '23 12:07 danleydmello