当在生产环境中托管时,WebAPI存在于外部未公开的服务器上,因此OData响应中返回的各种链接(例如@ odata.context和@ odata.nextLink)指向内部IP地址,例如,http://192.168.X.X/\u0026lt; AccountName> / api / …等
我已经能够修改Request.ODataProperties().NextLink,在每个ODataController方法中实现一些逻辑,用一个外部URL替换内部URL,如https://account-name.domain.com/api/. ..,但这非常不方便,只能修复NextLinks.
有没有办法在OData服务的配置时设置外部主机名?我已经看到了一个属性Request.ODataProperties().路径并想知道是否可以在config.MapODataServiceRoute(“odata”,“odata”,GetModel())中设置基本路径;调用,或在GetModel()实现中使用例如ODataConventionModelBuilder?
更新:到目前为止我提出的最佳解决方案是创建一个BaSEODataController来覆盖Initialize方法并检查Request.RequestUri.Host.StartsWith(“begin-of-internal-IP-address”)然后执行RequestUri重写,如下所示:
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}");
这完美地修复了所有控制器的@ odata.nextLink URL,但由于某种原因,@ odata.context URL仍然获得AccountName部分(例如https://account-name.domain.com/AccountName/api/odata/ $Metadata#ControllerName),因此它们仍然不起作用.
解决方法
UrlHelper
计算的,它以某种方式引用原始请求URI的路径. (因此你在@ odata.context链接中看到的AccountName.我在我的代码中看到过这种行为,但是我无法找到缓存的URI路径的来源.)
我们可以通过创建CustomUrlHelper类来动态重写OData链接,而不是重写RequestUri.新的GetNextPageLink方法将处理@ odata.nextLink重写,而Link方法覆盖将处理所有其他重写.
public class CustomUrlHelper : System.Web.Http.Routing.UrlHelper { public CustomUrlHelper(HttpRequestMessage request) : base(request) { } // Change these strings to suit your specific needs. private static readonly string ODataRouteName = "ODataRoute"; // Must be the same as used in api config private static readonly string TargetPrefix = "http://localhost:8080/somePathPrefix"; private static readonly int TargetPrefixLength = TargetPrefix.Length; private static readonly string ReplacementPrefix = "http://www.contoso.com"; // Do not end with slash // Helper method. protected string ReplaceTargetPrefix(string link) { if (link.StartsWith(TargetPrefix)) { if (link.Length == TargetPrefixLength) { link = ReplacementPrefix; } else if (link[TargetPrefixLength] == '/') { link = ReplacementPrefix + link.Substring(TargetPrefixLength); } } return link; } public override string Link(string routeName,IDictionary<string,object> routeValues) { var link = base.Link(routeName,routeValues); if (routeName == ODataRouteName) { link = this.ReplaceTargetPrefix(link); } return link; } public Uri GetNextPageLink(int pageSize) { return new Uri(this.ReplaceTargetPrefix(this.Request.GetNextPageLink(pageSize).ToString())); } }
在基本控制器类的Initialize方法中连接CustomUrlHelper.
public abstract class BaSEODataController : ODataController { protected abstract int DefaultPageSize { get; } protected override void Initialize(System.Web.Http.Controllers.HttpControllerContext controllerContext) { base.Initialize(controllerContext); var helper = new CustomUrlHelper(controllerContext.Request); controllerContext.RequestContext.Url = helper; controllerContext.Request.ODataProperties().NextLink = helper.GetNextPageLink(this.DefaultPageSize); }
请注意,在给定的控制器类中,页面大小对于所有操作都是相同的.您可以通过将ODataProperties().NextLink的赋值移动到特定操作方法的主体来解决此限制,如下所示:
var helper = this.RequestContext.Url as CustomUrlHelper; this.Request.ODataProperties().NextLink = helper.GetNextPageLink(otherPageSize);