AspNetCoreOData
AspNetCoreOData copied to clipboard
@odata.context url for navigation property
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"}
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?
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"}
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.
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 yes we have a fix. Hope to get it merged soon.
@ElizabethOkerio, any update on this?
Thanks
@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.
...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 @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 will follow up on this work item this week. Will get back to you.
@ElizabethOkerio , any update yet?
@xuzhg
@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 , same problem we are facing, the PowerBI OData feed fails to handle the response in this situation
@mikepizzo @ElizabethOkerio -- could we get an update on this please? This issue is still blocking us.
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.
@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.
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.
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"
}
]
}
The response seems to be Ok. Could you please share your repro? Are you using a dynamic model?
I see you are using a collection, the issue talks about a reference to a single type...
@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"
}
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
Yes looking into this.
@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 , 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 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"
}
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.