Open lf-novelt opened 3 months ago
this is where the request.Uri is passed to the GetNextLink function, we can clearly see it does not use the BaseAddressFactory and it should not be hard to add it here (NB: this is not the only place GetNextPageLink is called, not certain this is the correct place)
The inconsistency of behavior across the @odata.context
and @odata.nextlink
results does seem to be a clear indicator of a bug to me on this one.
@lf-novelt the next page link url is generated by the SkipTokenHandler
. You can create a custom SkipTokenHandler
that overwrites the default one and rewrites the URL to replace private host with the public one. Here's a guide on customizing the SkipTokenHandler: https://learn.microsoft.com/en-us/odata/webapi-8/tutorials/custom-skiptokenhandler
I do agree that it's on obvious, and it's confusing, that you would have to change the URL in multiple locations. There's a room to improve the design, but I don't think SkipTokenHandler
should have a dependency on ODataOutputFormatter.BaseAddressFactory
.
hey @habbes , thanks for the followup.
good point, indeed I was not aware of this SkipTokenHandler
, however when reading the doc, it seems more suited to allow customize the $skipToken
value rather than the baseUri
.
Indeed the baseUri
is passed as parameter of the GenerateNextPageLink
method, so why not pass the customized base url directly to it?
The input baseUri
seems generated here, so in the Formatter section so it does not seem irrelevant to call the ODataOutputFormatter.BaseAddressFactory
here, when passing the new Uri(writeContext.Request.GetEncodedUrl()
parameter, does it?
https://github.com/OData/AspNetCoreOData/blob/599dc1bdca9edc2cf88935ed54fe46ad5478da5b/src/Microsoft.AspNetCore.OData/Formatter/Serialization/ODataCollectionSerializer.cs#L112
Assemblies affected
Microsoft.AspNetCore.OData.Formatter
8.2.5Microsoft.AspNetCore.OData.Extensions
Describe the bug The odata app is hosted behind multiple proxies. It needs to send the publicly exposed urls back to the client rather than the app service internal urls. I've checked the solution proposed in https://github.com/OData/AspNetCoreOData/issues/876 but it does not fully resolve the problem as the whole url needs to be changed, not only the Host. I think that's the purpose of
ODataOutputFormatter.BaseAddressFactory
.As stated in the doc,
ODataOutputFormatter.BaseAddressFactory
is supposed to "Gets or sets a method that allows consumers to provide an alternate base address for OData Uri.". It works well by altering the main@odata.context
urls but when a set has too many rows and a@odata.nextlink
is generated, the url is still computed using only the original request. That leads to mixed urls in the same OData response. One would expect all OData generated urls would be managed by this output formatter.Reproduce steps Register a custom
ODataOutputFormatter.BaseAddressFactory
inProgram.cs
and set a low MaxTop to trigger thenextLink
and request any endpoint with more entities than MaxTop value without$top
.Data Model
Schools
entity from the default template, does not matter here.Request/Response In this example, the private url is
https://localhost:44345/odata/
and should be rewritten tohttps://localhost:5001/
. Please share your request Uri, head or the request body https://localhost:44345/odata/SYS_ANOTHERDATASOURCE/Schools Please share your response head, body.**Expand response body json**
```json { "@odata.context": "https://localhost:5001/SYS_ANOTHERDATASOURCE/$metadata#Schools", "@odata.count": 12, "value": [ { "ID": 100, "CreatedDay": null }, { "ID": 101, "CreatedDay": null }, { "ID": 102, "CreatedDay": null }, { "ID": 103, "CreatedDay": null }, { "ID": 104, "CreatedDay": null }, { "ID": 105, "CreatedDay": null }, { "ID": 106, "CreatedDay": null }, { "ID": 107, "CreatedDay": null }, { "ID": 108, "CreatedDay": null }, { "ID": 109, "CreatedDay": null } ], "@odata.nextLink": "https://localhost:44345/odata/SYS_ANOTHERDATASOURCE/Schools?$skip=10" } ```Expected behavior The
@odata.nextLink
url should be processed by the custom providedBaseAddressFactory
Screenshots