I'm using WebAPI 2.2 and Microsoft.AspNet.OData 5.7.0 to create an OData service that supports paging.
When hosted in the production environment, the WebAPI lives on a server that is not exposed externally, hence the various links returned in the OData response such as the @odata.context
and @odata.nextLink
point to the internal IP address e.g. http://192.168.X.X/<AccountName>/api/...
etc.
I've been able to modify the Request.ODataProperties().NextLink
by implementing some logic in each and every ODataController method to replace the internal URL with an external URL like https://account-name.domain.com/api/...
, but this is very inconvenient and it only fixes the NextLinks.
Is there some way to set an external host name at configuration time of the OData service? I've seen a property Request.ODataProperties().Path
and wonder if it's possible to set a base path at the config.MapODataServiceRoute("odata", "odata", GetModel());
call, or in the GetModel()
implementation using for instance the ODataConventionModelBuilder
?
UPDATE: The best solution I've come up with so far, is to create a BaseODataController
that overrides the Initialize
method and checks whether the Request.RequestUri.Host.StartsWith("beginning-of-known-internal-IP-address")
and then do a RequestUri rewrite like so:
var externalAddress = ConfigClient.Get().ExternalAddress; // e.g. https://account-name.domain.com
var account = ConfigClient.Get().Id; // e.g. AccountName
var uriToReplace = new Uri(new Uri("http://" + Request.RequestUri.Host), account);
string originalUri = Request.RequestUri.AbsoluteUri;
Request.RequestUri = new Uri(Request.RequestUri.AbsoluteUri.Replace(uriToReplace.AbsoluteUri, externalAddress));
string newUri = Request.RequestUri.AbsoluteUri;
this.GetLogger().Info($"Request URI was rewritten from {originalUri} to {newUri}");
This perfectly fixes the @odata.nextLink
URLs for all controllers, but for some reason the @odata.context
URLs still get the AccountName
part (e.g. https://account-name.domain.com/AccountName/api/odata/$metadata#ControllerName) so they still don't work.
Rewriting the
RequestUri
is sufficient to affect@odata.nextLink
values because the code that computes the next link depends on theRequestUri
directly. The other@odata.xxx
links are computed via aUrlHelper
, which is somehow referencing the path from the original request URI. (Hence theAccountName
you see in your@odata.context
link. I've seen this behavior in my code, but I haven't been able to track down the source of the cached URI path.)Rather than rewrite the
RequestUri
, we can solve the problem by creating aCustomUrlHelper
class to rewrite OData links on the fly. The newGetNextPageLink
method will handle@odata.nextLink
rewrites, and theLink
method override will handle all other rewrites.Wire-up the
CustomUrlHelper
in theInitialize
method of a base controller class.Note in the above that the page size will be the same for all actions in a given controller class. You can work around this limitation by moving the assignment of
ODataProperties().NextLink
to the body of a specific action method as follows: