Override host of webapi odata links

后端 未结 6 1743
Happy的楠姐
Happy的楠姐 2020-12-06 19:55

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 o

6条回答
  •  遥遥无期
    2020-12-06 20:54

    Rewriting the RequestUri is sufficient to affect @odata.nextLink values because the code that computes the next link depends on the RequestUri directly. The other @odata.xxx links are computed via a UrlHelper, which is somehow referencing the path from the original request URI. (Hence the AccountName 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 a CustomUrlHelper class to rewrite OData links on the fly. The new GetNextPageLink method will handle @odata.nextLink rewrites, and the Link method override will handle all other rewrites.

    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 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()));
        }
    }
    

    Wire-up the CustomUrlHelper in the Initialize method of a base controller class.

    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);
        }
    

    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:

    var helper = this.RequestContext.Url as CustomUrlHelper;
    this.Request.ODataProperties().NextLink = helper.GetNextPageLink(otherPageSize);
    

提交回复
热议问题