コード例 #1
0
 /// <summary>
 /// Generates an OData link using the default OData route name.
 /// </summary>
 /// <param name="urlHelper">The URL helper.</param>
 /// <param name="pathHandler">The path handler to use for generating the link.</param>
 /// <param name="segments">The OData path segments.</param>
 /// <returns>The geerated OData link.</returns>
 public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, IList<ODataPathSegment> segments)
 {
     string odataPath = pathHandler.Link(new ODataPath(segments));
     return urlHelper.Link(
         ODataRouteConstants.RouteName,
         new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } });
 }
コード例 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataPathRouteConstraint" /> class.
        /// </summary>
        /// <param name="pathHandler">The OData path handler to use for parsing.</param>
        /// <param name="model">The EDM model to use for parsing the path.</param>
        /// <param name="routeName">The name of the route this constraint is associated with.</param>
        /// <param name="routingConventions">The OData routing conventions to use for selecting the controller name.</param>
        public ODataPathRouteConstraint(IODataPathHandler pathHandler, IEdmModel model, string routeName, IEnumerable<IODataRoutingConvention> routingConventions)
        {
            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (routeName == null)
            {
                throw Error.ArgumentNull("routeName");
            }

            if (routingConventions == null)
            {
                throw Error.ArgumentNull("routingConventions");
            }

            PathHandler = pathHandler;
            EdmModel = model;
            RouteName = routeName;
            RoutingConventions = routingConventions;
        }
コード例 #3
0
        /// <summary>
        /// Generates an OData link using the given OData route name and path handler.
        /// </summary>
        /// <param name="urlHelper">The URL helper.</param>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments)
        {
            if (urlHelper == null)
            {
                throw Error.ArgumentNull("urlHelper");
            }

            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            string odataPath = pathHandler.Link(new ODataPath(segments));

            string directLink = urlHelper.GenerateLinkDirectly(routeName, odataPath);
            if (directLink != null)
            {
                return directLink;
            }

            // Slow path : use urlHelper.Link because the fast path failed
            return urlHelper.Link(
                routeName,
                new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } });
        }
コード例 #4
0
        public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model,
            IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            if (!String.IsNullOrEmpty(routePrefix))
            {
                int routePrefixLastCharIndex = routePrefix.Length - 1;
                if (routePrefix[routePrefixLastCharIndex] != '/')
                {
                    // Add the last trailing slash if it doesn't have one.
                    routePrefix += "/";
                }
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                routes.MapHttpBatchRoute(routeName + "Batch", routePrefix + ODataRouteConstants.Batch, batchHandler);
            }

            string routeTemplate = routePrefix + ODataRouteConstants.ODataPathTemplate;
            IHttpRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            HttpRouteValueDictionary constraintDictionary = new HttpRouteValueDictionary() { { ODataRouteConstants.ConstraintName, routeConstraint } };
            routes.MapHttpRoute(routeName, routeTemplate, defaults: null, constraints: constraintDictionary);
        }
        /// <summary>
        /// Map odata route with query string or header constraints
        /// </summary>
        public static void MapODataRoute(
            this HttpRouteCollection routes,
            string routeName,
            string routePrefix,
            IEdmModel model,
            IODataPathHandler pathHandler,
            IEnumerable<IODataRoutingConvention> routingConventions,
            object queryConstraints,
            object headerConstraints)
        {
            if (routes == null)
            {
                throw new ArgumentNullException("routes");
            }

            string routeTemplate = string.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.ODataPathTemplate : (routePrefix + "/" + ODataRouteConstants.ODataPathTemplate);
            ODataVersionRouteConstraint routeConstraint = new ODataVersionRouteConstraint(pathHandler, model, routeName, routingConventions, queryConstraints, headerConstraints);
            var constraints = new HttpRouteValueDictionary();
            constraints.Add(ODataRouteConstants.ConstraintName, routeConstraint);
            routes.MapHttpRoute(
                routeName,
                routeTemplate,
                defaults: null,
                constraints: constraints);
        }
コード例 #6
0
        public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model,
            IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            if (!String.IsNullOrEmpty(routePrefix))
            {
                int prefixLastIndex = routePrefix.Length - 1;
                if (routePrefix[prefixLastIndex] == '/')
                {
                    // Remove the last trailing slash if it has one.
                    routePrefix = routePrefix.Substring(0, routePrefix.Length - 1);
                }
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            routes.Add(routeName, new ODataRoute(routePrefix, routeConstraint));
        }
コード例 #7
0
 /// <summary>
 /// Maps the specified OData route.
 /// </summary>
 /// <param name="routes">A collection of routes for the application.</param>
 /// <param name="routeName">The name of the route to map.</param>
 /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
 /// <param name="model">The EDM model to use for parsing OData paths.</param>
 /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param>
 /// <param name="routingConventions">
 /// The OData routing conventions to use for controller and action selection.
 /// </param>
 /// <returns>The added <see cref="ODataRoute"/>.</returns>
 public static ODataRoute MapODataServiceRoute(this HttpRouteCollection routes, string routeName,
     string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
     IEnumerable<IODataRoutingConvention> routingConventions)
 {
     return MapODataServiceRoute(routes, routeName, routePrefix, model, pathHandler, routingConventions,
         batchHandler: null);
 }
コード例 #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DefaultODataPathRouteConstraint" /> class.
 /// </summary>
 /// <param name="pathHandler">The path handler.</param>
 /// <param name="model">The EDM model.</param>
 /// <param name="routeName">The name of the route.</param>
 /// <param name="routingConventions">The routing convention.</param>
 public DefaultODataPathRouteConstraint(
     IODataPathHandler pathHandler,
     IEdmModel model,
     string routeName,
     IEnumerable<IODataRoutingConvention> routingConventions)
     : base(pathHandler, model, routeName, routingConventions)
 {
 }
 public CustomODataPathRouteConstraint(
     IODataPathHandler pathHandler,
     Func<HttpRequestMessage, IEdmModel> modelProvider,
     string routeName,
     IEnumerable<IODataRoutingConvention> routingConventions)
     : base(pathHandler, new EdmModel(), routeName, routingConventions)
 {
     EdmModelProvider = modelProvider;
 }
コード例 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataPathRouteConstraint" /> class.
        /// </summary>
        /// <param name="pathHandler">The OData path handler to use for parsing.</param>
        public ODataPathRouteConstraint(IODataPathHandler pathHandler)
        {
            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            _pathHandler = pathHandler;
        }
コード例 #11
0
 public ODataVersionRouteConstraint(
     IODataPathHandler pathHandler,
     IEdmModel model,
     string routeName,
     IEnumerable<IODataRoutingConvention> routingConventions,
     object queryConstraints,
     object headerConstraints)
     : base(pathHandler, model, routeName, routingConventions)
 {
     QueryStringConstraints = new HttpRouteValueDictionary(queryConstraints);
     HeaderConstraints = new HttpRouteValueDictionary(headerConstraints);
 }
コード例 #12
0
        /// <summary>
        /// Maps the specified OData route.
        /// </summary>
        /// <param name="routes">A collection of routes for the application.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="model">The EDM model to use for parsing OData paths.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param>
        /// <param name="routingConventions">The OData routing conventions to use for controller and action selection.</param>
        public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model,
            IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            string routeTemplate = String.IsNullOrEmpty(routePrefix) ?
                ODataRouteConstants.ODataPathTemplate :
                routePrefix + "/" + ODataRouteConstants.ODataPathTemplate;
            IHttpRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            HttpRouteValueDictionary constraintDictionary = new HttpRouteValueDictionary() { { ODataRouteConstants.ConstraintName, routeConstraint } };
            routes.MapHttpRoute(routeName, routeTemplate, defaults: null, constraints: constraintDictionary);
        }
コード例 #13
0
        /// <summary>
        /// Generates an OData link using the given OData route name and path handler.
        /// </summary>
        /// <param name="urlHelper">The URL helper.</param>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler, IList<ODataPathSegment> segments)
        {
            if (urlHelper == null)
            {
                throw Error.ArgumentNull("urlHelper");
            }

            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            string odataPath = pathHandler.Link(new ODataPath(segments));
            return urlHelper.Link(
                routeName,
                new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } });
        }
コード例 #14
0
        /// <summary>
        /// Generates an OData link using the given OData route name, path handler, and segments.
        /// </summary>
        /// <param name="urlHelper">The URL helper.</param>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler,
            IList<ODataPathSegment> segments)
        {
            //if (urlHelper == null)
            //{
            //    throw Error.ArgumentNull("urlHelper");
            //}

            //if (pathHandler == null)
            //{
            //    throw Error.ArgumentNull("pathHandler");
            //}

            //string odataPath = pathHandler.Link(new ODataPath(segments));
            //return urlHelper.Link(
            //     routeName,
            //     new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } });
            return "http://service-root/";
        }
コード例 #15
0
        private static ODataRoute CustomMapODataServiceRoute(
            HttpRouteCollection routes,
            string routeName,
            string routePrefix,
            Func<HttpRequestMessage, IEdmModel> modelProvider,
            IODataPathHandler pathHandler,
            IEnumerable<IODataRoutingConvention> routingConventions,
            ODataBatchHandler batchHandler)
        {
            if (!string.IsNullOrEmpty(routePrefix))
            {
                int prefixLastIndex = routePrefix.Length - 1;
                if (routePrefix[prefixLastIndex] == '/')
                {
                    routePrefix = routePrefix.Substring(0, routePrefix.Length - 1);
                }
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = string.IsNullOrEmpty(routePrefix)
                    ? ODataRouteConstants.Batch
                    : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            CustomODataPathRouteConstraint routeConstraint = new CustomODataPathRouteConstraint(
                pathHandler,
                modelProvider,
                routeName,
                routingConventions);
            CustomODataRoute odataRoute = new CustomODataRoute(routePrefix, routeConstraint);
            routes.Add(routeName, odataRoute);

            return odataRoute;
        }
コード例 #16
0
 /// <summary>
 /// Maps the specified OData route.
 /// </summary>
 /// <param name="routes">A collection of routes for the application.</param>
 /// <param name="routeName">The name of the route to map.</param>
 /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
 /// <param name="model">The EDM model to use for parsing OData paths.</param>
 /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param>
 /// <param name="routingConventions">The OData routing conventions to use for controller and action selection.</param>
 public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model,
                                  IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions)
 {
     routes.MapODataRoute(routeName, routePrefix, model, pathHandler, routingConventions, batchHandler: null);
 }
コード例 #17
0
        /// <summary>
        /// Generates an OData link using the given OData route name, path handler, and segments.
        /// </summary>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string CreateODataLink(ResourceContext context, string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments)
        {
#if NETCORE
            return(context.Request.HttpContext.GetUrlHelper().CreateODataLink(routeName, pathHandler, segments));
#else
            return(context.Url.CreateODataLink(routeName, pathHandler, segments));
#endif
        }
コード例 #18
0
 /// <summary>
 /// Generates an OData link using the default OData route name.
 /// </summary>
 /// <param name="urlHelper">The URL helper.</param>
 /// <param name="pathHandler">The path handler to use for generating the link.</param>
 /// <param name="segments">The OData path segments.</param>
 /// <returns>The generated OData link.</returns>
 public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, params ODataPathSegment[] segments)
 {
     return(urlHelper.ODataLink(pathHandler, segments as IList <ODataPathSegment>));
 }
コード例 #19
0
        public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
            string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
            IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            HttpRouteCollection routes = configuration.Routes;
            routePrefix = RemoveTrailingSlash(routePrefix);

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch
                    : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler;
            if (odataPathHandler != null)
            {
                odataPathHandler.ResolverSetttings = configuration.GetResolverSettings();
            }

            ODataPathRouteConstraint routeConstraint =
                new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            ODataRoute route = new ODataRoute(routePrefix, routeConstraint);
            routes.Add(routeName, route);
            return route;
        }
コード例 #20
0
        public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
                                                      string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                                      IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            HttpRouteCollection routes = configuration.Routes;

            routePrefix = RemoveTrailingSlash(routePrefix);

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch
                    : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            DefaultODataPathHandler odataPathHanlder = pathHandler as DefaultODataPathHandler;

            if (odataPathHanlder != null)
            {
                odataPathHanlder.ResolverSetttings = configuration.GetResolverSettings();
            }

            ODataPathRouteConstraint routeConstraint =
                new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            ODataRoute route = new ODataRoute(routePrefix, routeConstraint);

            routes.Add(routeName, route);
            return(route);
        }
コード例 #21
0
        public static ODataRoute MapODataServiceRoute(this HttpRouteCollection routes, string routeName,
                                                      string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                                      IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            if (!String.IsNullOrEmpty(routePrefix))
            {
                int prefixLastIndex = routePrefix.Length - 1;
                if (routePrefix[prefixLastIndex] == '/')
                {
                    // Remove the last trailing slash if it has one.
                    routePrefix = routePrefix.Substring(0, routePrefix.Length - 1);
                }
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch
                    : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            ODataPathRouteConstraint routeConstraint =
                new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            ODataRoute route = new ODataRoute(routePrefix, routeConstraint);

            routes.Add(routeName, route);
            return(route);
        }
コード例 #22
0
        /// <summary>
        /// Generates an OData link using the given OData route name, path handler, and segments.
        /// </summary>
        /// <param name="urlHelper">The URL helper.</param>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler,
                                             IList <ODataPathSegment> segments)
        {
            //if (urlHelper == null)
            //{
            //    throw Error.ArgumentNull("urlHelper");
            //}

            //if (pathHandler == null)
            //{
            //    throw Error.ArgumentNull("pathHandler");
            //}

            //string odataPath = pathHandler.Link(new ODataPath(segments));
            //return urlHelper.Link(
            //     routeName,
            //     new HttpRouteValueDictionary() { { ODataRouteConstants.ODataPath, odataPath } });
            return("http://service-root/");
        }
コード例 #23
0
 public static void SetODataPathHandler(this HttpRequestMessage request, IODataPathHandler pathHandler)
 {
     Extensions.HttpRequestMessageExtensions.ODataProperties(request).PathHandler = pathHandler;
 }
コード例 #24
0
        private static void SetResolverSettings( this HttpConfiguration configuration, IODataPathHandler pathHandler )
        {
            Contract.Requires( configuration != null );

            // REMARKS: the DefaultODataPathHandler.ResolverSettings property is internal as is the ODataUriResolverSetttings class.
            // The MapODataServiceRoute normally hooks this up, but we are replacing that process. in order to retain functional
            // fidelity we'll build and compile a strong-typed delegate that can be used to set the property.
            //
            // in additional, the ODataUriResolverSetttings are created lazy-initialized from the property bag. instead of using
            // Reflection, we'll test for the known key. if the key is not present, we'll use a public extension method
            // (e.g. EnableCaseInsensitive) with the default, unconfigured value. this will trigger the creation of the
            // settings and populate the property.

            var handler = pathHandler as DefaultODataPathHandler;

            if ( handler == null )
            {
                return;
            }

            // REMARKS: this creates and populates the ODataUriResolverSetttings; OData URLs are case-sensitive by default.
            if ( !configuration.Properties.ContainsKey( ResolverSettingsKey ) )
            {
                configuration.EnableCaseInsensitive( false );
            }

            setResolverSettings.Value( handler, configuration.Properties[ResolverSettingsKey] );
        }
        /// <summary>
        /// Sets the <see cref="IODataPathHandler"/> to use for generating links.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for generating links.</param>
        public static void SetODataPathHandler(this HttpRequestMessage request, IODataPathHandler pathHandler)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            request.Properties[ODataPathHandlerKey] = pathHandler;
        }
コード例 #26
0
        /// <summary>
        /// Determines whether this instance equals a specified route.
        /// </summary>
        /// <param name="httpContext">The http context.</param>
        /// <param name="route">The route to compare.</param>
        /// <param name="routeKey">The name of the route key.</param>
        /// <param name="values">A list of parameter values.</param>
        /// <param name="routeDirection">The route direction.</param>
        /// <returns>
        /// True if this instance equals a specified route; otherwise, false.
        /// </returns>
        public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values,
                          RouteDirection routeDirection)
        {
            if (httpContext == null)
            {
                throw Error.ArgumentNull("httpContext");
            }

            if (values == null)
            {
                throw Error.ArgumentNull("values");
            }

            if (routeDirection == RouteDirection.IncomingRequest)
            {
                object odataPathValue;
                if (!values.TryGetValue(ODataRouteConstants.ODataPath, out odataPathValue))
                {
                    return(false);
                }

                string    odataPathString = odataPathValue as string;
                ODataPath odataPath;

                try
                {
                    // Service root is the current RequestUri, less the query string and the ODataPath (always the
                    // last portion of the absolute path).  ODL expects an escaped service root and other service
                    // root calculations are calculated using AbsoluteUri (also escaped).  But routing exclusively
                    // uses unescaped strings, determined using
                    //    address.GetComponents(UriComponents.Path, UriFormat.Unescaped)
                    //
                    // For example if the AbsoluteUri is
                    // <http://localhost/odata/FunctionCall(p0='Chinese%E8%A5%BF%E9%9B%85%E5%9B%BEChars')>, the
                    // oDataPathString will contain "FunctionCall(p0='Chinese西雅图Chars')".
                    //
                    // Due to this decoding and the possibility of unecessarily-escaped characters, there's no
                    // reliable way to determine the original string from which oDataPathString was derived.
                    // Therefore a straightforward string comparison won't always work.  See RemoveODataPath() for
                    // details of chosen approach.
                    HttpRequest request = httpContext.Request;

                    string serviceRoot = GetServiceRoot(request);

                    // string requestLeftPart = request.Path..GetLeftPart(UriPartial.Path);
                    //string serviceRoot = request.Path;

                    /*
                     * if (!String.IsNullOrEmpty(odataPathString))
                     * {
                     *  serviceRoot = RemoveODataPath(serviceRoot, odataPathString);
                     * }*/

                    // As mentioned above, we also need escaped ODataPath.
                    // The requestLeftPart and request.RequestUri.Query are both escaped.
                    // The ODataPath for service documents is empty.
                    string oDataPathAndQuery = String.Empty;
                    if (!String.IsNullOrEmpty(odataPathString))
                    {
                        oDataPathAndQuery = odataPathString;
                    }

                    if (request.QueryString.HasValue)
                    {
                        // Ensure path handler receives the query string as well as the path.
                        oDataPathAndQuery += request.QueryString;
                    }

                    // Leave an escaped '/' out of the service route because DefaultODataPathHandler will add a
                    // literal '/' to the end of this string if not already present. That would double the slash
                    // in response links and potentially lead to later 404s.
                    if (serviceRoot.EndsWith(_escapedSlash, StringComparison.OrdinalIgnoreCase))
                    {
                        serviceRoot = serviceRoot.Substring(0, serviceRoot.Length - _escapedSlash.Length);
                    }

                    IODataPathHandler pathHandler = httpContext.RequestServices.GetRequiredService <IODataPathHandler>();
                    odataPath = pathHandler.Parse(_model, serviceRoot, oDataPathAndQuery, httpContext.ODataFeature().UriResolverSettings);
                }
                catch (ODataException odataException)
                {
                    odataPath = null;
                }

                if (odataPath != null)
                {
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.Model = _model;
                    odataFeature.IsValidODataRequest = true;
                    odataFeature.Path        = odataPath;
                    odataFeature.RoutePrefix = _routePrefix;
                    return(true);
                }
                else
                {
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.IsValidODataRequest = false;
                    return(false);
                }
            }
            // This constraint only applies to incomming request.
            return(false);
        }
コード例 #27
0
 /// <summary>
 /// Generates an OData link using the given OData route name, path handler, and segments.
 /// </summary>
 /// <param name="routeName">The name of the OData route.</param>
 /// <param name="pathHandler">The path handler to use for generating the link.</param>
 /// <param name="segments">The OData path segments.</param>
 /// <returns>The generated OData link.</returns>
 public string CreateODataLink(string routeName, IODataPathHandler pathHandler, IList <ODataPathSegment> segments)
 {
     return(this.innerHelper.CreateODataLink(routeName, pathHandler, segments));
 }
コード例 #28
0
        public override bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary <string, object> values, HttpRouteDirection routeDirection)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            if (routeDirection == HttpRouteDirection.UriResolution)
            {
                if (values.TryGetValue(ODataRouteConstants.ODataPath, out object oDataPathValue))
                {
                    string    oDataPathString = oDataPathValue as string;
                    ODataPath path;

                    try
                    {
                        IServiceProvider            requestContainer           = request.CreateRequestContainer(this.RouteName);
                        IHttpRequestMessageProvider httpRequestMessageProvider = requestContainer.GetRequiredService <IHttpRequestMessageProvider>();
                        httpRequestMessageProvider.Request = request;

                        string[] segments   = oDataPathString.Split('/');
                        string   dataSource = segments[0];
                        request.Properties[Constants.ODataDataSource] = dataSource;
                        request.Properties[Constants.CustomODataPath] = string.Join("/", segments, 1, segments.Length - 1);
                        oDataPathString = (string)request.Properties[Constants.CustomODataPath];

                        // Service root is the current RequestUri, less the query string and the ODataPath (always the
                        // last portion of the absolute path).  ODL expects an escaped service root and other service
                        // root calculations are calculated using AbsoluteUri (also escaped).  But routing exclusively
                        // uses unescaped strings, determined using
                        //    address.GetComponents(UriComponents.Path, UriFormat.Unescaped)
                        //
                        // For example if the AbsoluteUri is
                        // <http://localhost/odata/FunctionCall(p0='Chinese%E8%A5%BF%E9%9B%85%E5%9B%BEChars')>, the
                        // oDataPathString will contain "FunctionCall(p0='Chinese西雅图Chars')".
                        //
                        // Due to this decoding and the possibility of unecessarily-escaped characters, there's no
                        // reliable way to determine the original string from which oDataPathString was derived.
                        // Therefore a straightforward string comparison won't always work.  See RemoveODataPath() for
                        // details of chosen approach.
                        string requestLeftPart = request.RequestUri.GetLeftPart(UriPartial.Path);
                        string serviceRoot     = requestLeftPart;
                        if (!string.IsNullOrEmpty(oDataPathString))
                        {
                            serviceRoot = RemoveODataPath(serviceRoot, oDataPathString);
                        }

                        // As mentioned above, we also need escaped ODataPath.
                        // The requestLeftPart and request.RequestUri.Query are both escaped.
                        // The ODataPath for service documents is empty.
                        string oDataPathAndQuery = requestLeftPart.Substring(serviceRoot.Length);
                        if (!string.IsNullOrEmpty(request.RequestUri.Query))
                        {
                            // Ensure path handler receives the query string as well as the path.
                            oDataPathAndQuery += request.RequestUri.Query;
                        }

                        // Leave an escaped '/' out of the service route because DefaultODataPathHandler will add a
                        // literal '/' to the end of this string if not already present. That would double the slash
                        // in response links and potentially lead to later 404s.
                        if (serviceRoot.EndsWith(escapedSlash, StringComparison.OrdinalIgnoreCase))
                        {
                            serviceRoot = serviceRoot.Substring(0, serviceRoot.Length - 3);
                        }

                        IODataPathHandler pathHandler = requestContainer.GetRequiredService <IODataPathHandler>();
                        path = pathHandler.Parse(serviceRoot, oDataPathAndQuery, requestContainer);
                    }
                    catch (ODataException)
                    {
                        path = null;
                    }

                    if (path != null)
                    {
                        // Set all the properties we need for routing, querying, formatting
                        request.ODataProperties().Path      = path;
                        request.ODataProperties().RouteName = this.RouteName;

                        if (!values.ContainsKey(ODataRouteConstants.Controller))
                        {
                            // Select controller name using the routing conventions
                            string controllerName = this.SelectControllerName(path, request);
                            if (controllerName != null)
                            {
                                values[ODataRouteConstants.Controller] = controllerName;
                            }
                        }

                        return(true);
                    }
                }

                // The request doesn't match this route so dipose the request container.
                request.DeleteRequestContainer(true);
                return(false);
            }
            else
            {
                // This constraint only applies to URI resolution
                return(true);
            }
        }
コード例 #29
0
 /// <summary>
 /// Maps the specified OData route.
 /// </summary>
 /// <param name="configuration">The server configuration.</param>
 /// <param name="routeName">The name of the route to map.</param>
 /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
 /// <param name="model">The EDM model to use for parsing OData paths.</param>
 /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param>
 /// <param name="routingConventions">
 /// The OData routing conventions to use for controller and action selection.
 /// </param>
 /// <returns>The added <see cref="ODataRoute"/>.</returns>
 public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
                                               string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                               IEnumerable <IODataRoutingConvention> routingConventions)
 {
     return(configuration.MapODataServiceRoute(routeName, routePrefix, builder =>
                                               builder.AddService(ServiceLifetime.Singleton, sp => model)
                                               .AddService(ServiceLifetime.Singleton, sp => pathHandler)
                                               .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable())));
 }
コード例 #30
0
 public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix,
                                  IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions)
 {
     Extensions.HttpRouteCollectionExtensions.MapODataServiceRoute(routes, routeName, routePrefix, model,
                                                                   pathHandler, routingConventions);
 }
コード例 #31
0
        private static IEndpointRouteBuilder MapDynamicODataServiceRoute(this IEndpointRouteBuilder builder, string routeName,
                                                                         string routePrefix, IODataPathHandler pathHandler,
                                                                         IEnumerable <IODataRoutingConvention> routingConventions,
                                                                         IDataSource dataSource)
        {
            ServiceProviderServiceExtensions.GetRequiredService <ApplicationPartManager>(builder.ServiceProvider).ApplicationParts.Add(new AssemblyPart(typeof(DynamicODataController).Assembly));
            var odataRoute = builder.MapODataRoute(routeName, routePrefix, containerBuilder =>
            {
                containerBuilder
                .AddService <IEdmModel>(Microsoft.OData.ServiceLifetime.Singleton, sp => dataSource.Model)
                .AddService <IDataSource>(Microsoft.OData.ServiceLifetime.Scoped, sp => dataSource)
                .AddService(Microsoft.OData.ServiceLifetime.Scoped, sp => routingConventions.ToList().AsEnumerable());
                if (pathHandler != null)
                {
                    containerBuilder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => pathHandler);
                }
            });

            return(odataRoute);
        }
コード例 #32
0
 /// <summary>
 /// Generates an OData link using the default OData route name.
 /// </summary>
 /// <param name="urlHelper">The URL helper.</param>
 /// <param name="pathHandler">The path handler to use for generating the link.</param>
 /// <param name="segments">The OData path segments.</param>
 /// <returns>The generated OData link.</returns>
 public static string ODataLink(this UrlHelper urlHelper, IODataPathHandler pathHandler, params ODataPathSegment[] segments)
 {
     return urlHelper.ODataLink(pathHandler, segments as IList<ODataPathSegment>);
 }
コード例 #33
0
 /// <summary>
 /// Maps the specified OData route. When the <paramref name="batchHandler"/> is non-<c>null</c>, it will
 /// create a '$batch' endpoint to handle the batch requests.
 /// </summary>
 /// <param name="builder">The <see cref="IRouteBuilder"/> to add the route to.</param>
 /// <param name="routeName">The name of the route to map.</param>
 /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
 /// <param name="model">The EDM model to use for parsing OData paths.</param>
 /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param>
 /// <param name="routingConventions">
 /// The OData routing conventions to use for controller and action selection.
 /// </param>
 /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param>
 /// <returns>The added <see cref="ODataRoute"/>.</returns>
 public static ODataRoute MapODataServiceRoute(this IRouteBuilder builder, string routeName,
                                               string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                               IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
 {
     return(builder.MapODataServiceRoute(routeName, routePrefix, containerBuilder =>
                                         containerBuilder.AddService(ServiceLifetime.Singleton, sp => model)
                                         .AddService(ServiceLifetime.Singleton, sp => pathHandler)
                                         .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable())
                                         .AddService(ServiceLifetime.Singleton, sp => batchHandler)));
 }
コード例 #34
0
 public static void SetODataPathHandler(this HttpRequestMessage request, IODataPathHandler pathHandler)
 {
     Extensions.HttpRequestMessageExtensions.ODataProperties(request).PathHandler = pathHandler;
 }
コード例 #35
0
        /// <summary>
        /// Maps the specified OData route. When the <paramref name="defaultHandler"/> is non-<c>null</c>, it will map
        /// it as the handler for the route.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="model">The EDM model to use for parsing OData paths.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param>
        /// <param name="routingConventions">
        /// The OData routing conventions to use for controller and action selection.
        /// </param>
        /// <param name="defaultHandler">The default <see cref="HttpMessageHandler"/> for this route.</param>
        /// <returns>The added <see cref="ODataRoute"/>.</returns>
        public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
                                                      string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                                      IEnumerable <IODataRoutingConvention> routingConventions, HttpMessageHandler defaultHandler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            // We have a more specific overload to map batch handlers that creates a different route for the batch
            // endpoint instead of mapping that handler as the per route handler. Given that HttpMessageHandler is a
            // base type of ODataBatchHandler, it's possible the compiler will call this overload instead of the one
            // for the batch handler, so we detect that case and call the appropiate overload for the user.
            // The case in which the compiler picks the wrong overload is:
            // HttpRequestMessageHandler batchHandler = new DefaultODataBatchHandler(httpServer);
            // config.Routes.MapODataServiceRoute("routeName", "routePrefix", model, batchHandler);
            if (defaultHandler != null)
            {
                ODataBatchHandler batchHandler = defaultHandler as ODataBatchHandler;
                if (batchHandler != null)
                {
                    return(MapODataServiceRoute(configuration, routeName, routePrefix, model, batchHandler));
                }
            }

            HttpRouteCollection routes = configuration.Routes;

            routePrefix = RemoveTrailingSlash(routePrefix);

            DefaultODataPathHandler odataPathHanlder = pathHandler as DefaultODataPathHandler;

            if (odataPathHanlder != null)
            {
                odataPathHanlder.ResolverSetttings = configuration.GetResolverSettings();
            }

            ODataPathRouteConstraint routeConstraint =
                new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            ODataRoute route = new ODataRoute(
                routePrefix,
                routeConstraint,
                defaults: null,
                constraints: null,
                dataTokens: null,
                handler: defaultHandler);

            routes.Add(routeName, route);
            return(route);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="T:System.Web.Http.OData.Routing.ODataPathRouteConstraint"/> class.
 /// </summary>
 /// <param name="pathHandler">The OData path handler to use for parsing.</param><param name="routeName">The name of the route this constraint is associated with.</param><param name="routingConventions">The OData routing conventions to use for selecting the controller name.</param>
 public EntityListODataPathRouteConstraint(IODataPathHandler pathHandler, string routeName,
                                           IEnumerable <IODataRoutingConvention> routingConventions) : base(pathHandler, CreateEmptyModel(), routeName, routingConventions)
 {
     EdmModel = CreateEmptyModel();
 }
コード例 #37
0
        /// <summary>
        /// Generates an OData link using the given OData route name, path handler, and segments.
        /// </summary>
        /// <param name="urlHelper">The URL helper.</param>
        /// <param name="routeName">The name of the OData route.</param>
        /// <param name="pathHandler">The path handler to use for generating the link.</param>
        /// <param name="segments">The OData path segments.</param>
        /// <returns>The generated OData link.</returns>
        public static string CreateODataLink(this IUrlHelper urlHelper, string routeName, IODataPathHandler pathHandler,
                                             IList <ODataPathSegment> segments)
        {
            if (urlHelper == null)
            {
                throw Error.ArgumentNull("urlHelper");
            }

            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            string odataPath = pathHandler.Link(new ODataPath(segments));

            return(urlHelper.Link(
                       routeName,
                       new RouteValueDictionary()
            {
                { ODataRouteConstants.ODataPath, odataPath }
            }));
        }
コード例 #38
0
 public ODataPathRouteConstraintTest()
 {
     _rootContainer = new MockContainer(_model, _conventions);
     _pathHandler   = _rootContainer.GetRequiredService <IODataPathHandler>();
 }
コード例 #39
0
 public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix,
     IEdmModel model, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions,
     ODataBatchHandler batchHandler)
 {
     Extensions.HttpRouteCollectionExtensions.MapODataServiceRoute(routes, routeName, routePrefix, model,
         pathHandler, routingConventions, batchHandler);
 }
コード例 #40
0
 public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler,
                                IList <ODataPathSegment> segments)
 {
     return(UrlHelperExtensions.CreateODataLink(urlHelper, routeName, pathHandler, segments));
 }
コード例 #41
0
        /// <summary>
        /// Maps the specified OData route. When the <paramref name="defaultHandler"/> is non-<c>null</c>, it will map
        /// it as the handler for the route.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="model">The EDM model to use for parsing OData paths.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param>
        /// <param name="routingConventions">
        /// The OData routing conventions to use for controller and action selection.
        /// </param>
        /// <param name="defaultHandler">The default <see cref="HttpMessageHandler"/> for this route.</param>
        /// <returns>The added <see cref="ODataRoute"/>.</returns>
        public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
            string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
            IEnumerable<IODataRoutingConvention> routingConventions, HttpMessageHandler defaultHandler)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            // We have a more specific overload to map batch handlers that creates a different route for the batch
            // endpoint instead of mapping that handler as the per route handler. Given that HttpMessageHandler is a
            // base type of ODataBatchHandler, it's possible the compiler will call this overload instead of the one
            // for the batch handler, so we detect that case and call the appropiate overload for the user.
            // The case in which the compiler picks the wrong overload is:
            // HttpRequestMessageHandler batchHandler = new DefaultODataBatchHandler(httpServer);
            // config.Routes.MapODataServiceRoute("routeName", "routePrefix", model, batchHandler);
            if (defaultHandler != null)
            {
                ODataBatchHandler batchHandler = defaultHandler as ODataBatchHandler;
                if (batchHandler != null)
                {
                    return MapODataServiceRoute(configuration, routeName, routePrefix, model, batchHandler);
                }
            }

            HttpRouteCollection routes = configuration.Routes;
            routePrefix = RemoveTrailingSlash(routePrefix);

            DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler;
            if (odataPathHandler != null)
            {
                odataPathHandler.ResolverSetttings = configuration.GetResolverSettings();
            }

            ODataPathRouteConstraint routeConstraint =
                new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            ODataRoute route = new ODataRoute(
                routePrefix,
                routeConstraint,
                defaults: null,
                constraints: null,
                dataTokens: null,
                handler: defaultHandler);
            routes.Add(routeName, route);
            return route;
        }
コード例 #42
0
        public static ODataPath Parse(this IODataPathHandler handler, IEdmModel model, string serviceRoot, string odataPath)
        {
            Contract.Assert(handler != null);

            return(handler.Parse(serviceRoot, odataPath, DefaultContainer));
        }
コード例 #43
0
        /// <summary>
        /// Maps the specified versioned OData routes. When the <paramref name="newBatchHandler"/> is provided, it will create a '$batch' endpoint to handle the batch requests.
        /// </summary>
        /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler">OData path handler</see> to use for parsing the OData path.</param>
        /// <param name="routingConventions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IODataRoutingConvention">OData routing conventions</see>
        /// to use for controller and action selection.</param>
        /// <param name="newBatchHandler">The <see cref="Func{TResult}">factory method</see> used to create new <see cref="ODataBatchHandler">OData batch handlers</see>.</param>
        /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns>
        /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>.  This annotation is
        /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to
        /// create the <paramref name="models"/>.</remarks>
        public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes(
            this IRouteBuilder builder,
            string routeName,
            string routePrefix,
            IEnumerable <IEdmModel> models,
            IODataPathHandler pathHandler,
            IEnumerable <IODataRoutingConvention> routingConventions,
            Func <ODataBatchHandler> newBatchHandler)
        {
            Arg.NotNull(builder, nameof(builder));
            Arg.NotNullOrEmpty(routeName, nameof(routeName));
            Arg.NotNull(models, nameof(models));
            Contract.Ensures(Contract.Result <IReadOnlyList <ODataRoute> >() != null);

            var serviceProvider          = builder.ServiceProvider;
            var options                  = serviceProvider.GetRequiredService <ODataOptions>();
            var routeCollection          = serviceProvider.GetRequiredService <IODataRouteCollectionProvider>();
            var inlineConstraintResolver = serviceProvider.GetRequiredService <IInlineConstraintResolver>();
            var routeConventions         = VersionedODataRoutingConventions.AddOrUpdate(routingConventions.ToList());
            var routes                 = builder.Routes;
            var perRouteContainer      = serviceProvider.GetRequiredService <IPerRouteContainer>();
            var odataRoutes            = new List <ODataRoute>();
            var unversionedConstraints = new List <IRouteConstraint>();

            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter;
            }

            foreach (var model in models)
            {
                var versionedRouteName = routeName;
                var apiVersion         = model.GetAnnotationValue <ApiVersionAnnotation>(model)?.ApiVersion;
                var routeConstraint    = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName);

                IEnumerable <IODataRoutingConvention> NewRouteConventions(IServiceProvider services)
                {
                    var conventions = new IODataRoutingConvention[routeConventions.Count + 1];

                    conventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName, serviceProvider, apiVersion);
                    routeConventions.CopyTo(conventions, 1);
                    return(conventions);
                }

                var edm             = model;
                var batchHandler    = newBatchHandler?.Invoke();
                var configureAction = builder.ConfigureDefaultServices(container =>
                                                                       container.AddService(Singleton, typeof(IEdmModel), sp => edm)
                                                                       .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler)
                                                                       .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), NewRouteConventions)
                                                                       .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler));
                var rootContainer = perRouteContainer.CreateODataRootContainer(versionedRouteName, configureAction);
                var router        = rootContainer.GetService <IRouter>() ?? builder.DefaultHandler;
                var route         = new ODataRoute(router, versionedRouteName, routePrefix.RemoveTrailingSlash(), routeConstraint, inlineConstraintResolver);

                unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName));
                builder.ConfigureBatchHandler(batchHandler, route);
                routes.Add(route);
                odataRoutes.Add(route);
                routeCollection.Add(new ODataRouteMapping(route, apiVersion, rootContainer));
            }

            builder.AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(routeName, routePrefix, unversionedConstraints, inlineConstraintResolver);
            NotifyRoutesMapped();

            return(odataRoutes);
        }
コード例 #44
0
        /// <summary>
        /// Maps the specified versioned OData routes. When the <paramref name="newBatchHandler"/> is provided, it will create a '$batch' endpoint to handle the batch requests.
        /// </summary>
        /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param>
        /// <param name="pathHandler">The <see cref="IODataPathHandler">OData path handler</see> to use for parsing the OData path.</param>
        /// <param name="routingConventions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IODataRoutingConvention">OData routing conventions</see>
        /// to use for controller and action selection.</param>
        /// <param name="newBatchHandler">The <see cref="Func{TResult}">factory method</see> used to create new <see cref="ODataBatchHandler">OData batch handlers</see>.</param>
        /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns>
        /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>.  This annotation is
        /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to
        /// create the <paramref name="models"/>.</remarks>
        public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes(
            this IRouteBuilder builder,
            string routeName,
            string routePrefix,
            IEnumerable <IEdmModel> models,
            IODataPathHandler pathHandler,
            IEnumerable <IODataRoutingConvention> routingConventions,
            Func <ODataBatchHandler>?newBatchHandler)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (IsNullOrEmpty(routeName))
            {
                throw new ArgumentNullException(nameof(routeName));
            }

            if (models == null)
            {
                throw new ArgumentNullException(nameof(models));
            }

            var serviceProvider          = builder.ServiceProvider;
            var options                  = serviceProvider.GetRequiredService <ODataOptions>();
            var routeCollection          = serviceProvider.GetRequiredService <IODataRouteCollectionProvider>();
            var inlineConstraintResolver = serviceProvider.GetRequiredService <IInlineConstraintResolver>();
            var routeConventions         = VersionedODataRoutingConventions.AddOrUpdate(routingConventions.ToList());
            var routes                 = builder.Routes;
            var perRouteContainer      = serviceProvider.GetRequiredService <IPerRouteContainer>();
            var odataRoutes            = new List <ODataRoute>();
            var unversionedConstraints = new List <IRouteConstraint>();

            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter;
            }

            foreach (var model in models)
            {
                var versionedRouteName = routeName;
                var annotation         = model.GetAnnotationValue <ApiVersionAnnotation>(model) ?? throw new ArgumentException(LocalSR.MissingAnnotation.FormatDefault(typeof(ApiVersionAnnotation).Name));
                var apiVersion         = annotation.ApiVersion;
                var routeConstraint    = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName);

                IEnumerable <IODataRoutingConvention> NewRouteConventions(IServiceProvider services)
                {
                    var conventions = new IODataRoutingConvention[routeConventions !.Count + 1];

                    conventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName !, serviceProvider !, apiVersion !);
                    routeConventions.CopyTo(conventions, 1);
                    return(conventions);
                }

                var edm             = model;
                var batchHandler    = newBatchHandler?.Invoke();
                var configureAction = builder.ConfigureDefaultServices(container =>
                                                                       container.AddService(Singleton, typeof(IEdmModel), sp => edm)
                                                                       .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler)
                                                                       .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), NewRouteConventions)
                                                                       .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler));
                var rootContainer = perRouteContainer.CreateODataRootContainer(versionedRouteName, configureAction);
                var router        = rootContainer.GetService <IRouter>() ?? builder.DefaultHandler;
                var route         = new ODataRoute(router, versionedRouteName, routePrefix.RemoveTrailingSlash(), routeConstraint, inlineConstraintResolver);

                unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName));
                builder.ConfigureBatchHandler(batchHandler, route);
                routes.Add(route);
                odataRoutes.Add(route);
                routeCollection.Add(new ODataRouteMapping(route, apiVersion, rootContainer));
            }
コード例 #45
0
        /// <summary>
        /// Maps the specified OData route and the OData route attributes.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        /// <returns>The added <see cref="ODataRoute"/>.</returns>
        public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
                                                      string routePrefix, Action <IContainerBuilder> configureAction)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            if (routeName == null)
            {
                throw Error.ArgumentNull("routeName");
            }

            // 1) Build and configure the root container.
            IServiceProvider rootContainer = configuration.CreateODataRootContainer(routeName, configureAction);

            // 2) Resolve the path handler and set URI resolver to it.
            IODataPathHandler pathHandler = rootContainer.GetRequiredService <IODataPathHandler>();

            // if settings is not on local, use the global configuration settings.
            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                ODataUrlKeyDelimiter urlKeyDelimiter = configuration.GetUrlKeyDelimiter();
                pathHandler.UrlKeyDelimiter = urlKeyDelimiter;
            }

            // 3) Resolve some required services and create the route constraint.
            ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(routeName);

            // Attribute routing must initialized before configuration.EnsureInitialized is called.
            rootContainer.GetServices <IODataRoutingConvention>();

            // 4) Resolve HTTP handler, create the OData route and register it.
            ODataRoute          route;
            HttpRouteCollection routes = configuration.Routes;

            routePrefix = RemoveTrailingSlash(routePrefix);
            HttpMessageHandler messageHandler = rootContainer.GetService <HttpMessageHandler>();

            if (messageHandler != null)
            {
                route = new ODataRoute(
                    routePrefix,
                    routeConstraint,
                    defaults: null,
                    constraints: null,
                    dataTokens: null,
                    handler: messageHandler);
            }
            else
            {
                ODataBatchHandler batchHandler = rootContainer.GetService <ODataBatchHandler>();
                if (batchHandler != null)
                {
                    batchHandler.ODataRouteName = routeName;
                    string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch
                        : routePrefix + '/' + ODataRouteConstants.Batch;
                    routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
                }

                route = new ODataRoute(routePrefix, routeConstraint);
            }

            routes.Add(routeName, route);
            return(route);
        }
コード例 #46
0
        public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes(
            this HttpConfiguration configuration,
            string routeName,
            string routePrefix,
            IEnumerable <IEdmModel> models,
            IODataPathHandler pathHandler,
            IEnumerable <IODataRoutingConvention> routingConventions,
            ODataBatchHandler batchHandler)
        {
            Arg.NotNull(configuration, nameof(configuration));
            Arg.NotNull(models, nameof(models));
            Contract.Ensures(Contract.Result <IReadOnlyList <ODataRoute> >() != null);

            var routeConventions     = EnsureConventions(routingConventions.ToList());
            var routes               = configuration.Routes;
            var unversionedRouteName = routeName + UnversionedRouteSuffix;

            if (!IsNullOrEmpty(routePrefix))
            {
                routePrefix = routePrefix.TrimEnd('/');
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = unversionedRouteName;
                var batchTemplate = IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + nameof(ODataRouteConstants.Batch), batchTemplate, batchHandler);
            }

            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                pathHandler.UrlKeyDelimiter = configuration.GetUrlKeyDelimiter();
            }

            routeConventions.Insert(0, null);

            var odataRoutes            = new List <ODataRoute>();
            var unversionedConstraints = new List <IHttpRouteConstraint>();

            foreach (var model in models)
            {
                var versionedRouteName = routeName;
                var apiVersion         = model.GetAnnotationValue <ApiVersionAnnotation>(model)?.ApiVersion;
                var routeConstraint    = MakeVersionedODataRouteConstraint(apiVersion, ref versionedRouteName);

                routeConventions[0] = new VersionedAttributeRoutingConvention(versionedRouteName, configuration, apiVersion);
                unversionedConstraints.Add(new ODataPathRouteConstraint(versionedRouteName));

                var edm           = model;
                var rootContainer = configuration.CreateODataRootContainer(
                    versionedRouteName,
                    builder => builder.AddService(Singleton, typeof(IEdmModel), sp => edm)
                    .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler)
                    .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), sp => routeConventions.ToArray())
                    .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler));

                rootContainer.InitializeAttributeRouting();

                var route          = default(ODataRoute);
                var messageHandler = rootContainer.GetService <HttpMessageHandler>();

                if (messageHandler == null)
                {
                    route = new ODataRoute(routePrefix, routeConstraint);
                }
                else
                {
                    route = new ODataRoute(routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: messageHandler);
                }

                routes.Add(versionedRouteName, route);
                AddApiVersionConstraintIfNecessary(route);
                odataRoutes.Add(route);
            }

            configuration.AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(unversionedRouteName, routePrefix, odataRoutes, unversionedConstraints, _ => { });

            return(odataRoutes);
        }
コード例 #47
0
        /// <summary>
        /// Sets the <see cref="IODataPathHandler"/> on the configuration.
        /// </summary>
        /// <param name="configuration">The server's configuration.</param>
        /// <param name="parser">The <see cref="IODataPathHandler"/> this configuration should use.</param>
        public static void SetODataPathHandler(this HttpConfiguration configuration, IODataPathHandler parser)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }
            if (parser == null)
            {
                throw Error.ArgumentNull("parser");
            }

            configuration.Properties[ODataPathHandlerKey] = parser;
        }
コード例 #48
0
        static ODataRoute MapVersionedODataRoute(
            HttpConfiguration configuration,
            string routeName,
            string routePrefix,
            IEdmModel model,
            ApiVersion apiVersion,
            IODataPathHandler pathHandler,
            IEnumerable <IODataRoutingConvention> routingConventions,
            ODataBatchHandler batchHandler,
            HttpMessageHandler defaultHandler)
        {
            Arg.NotNull(configuration, nameof(configuration));
            Arg.NotNull(model, nameof(model));
            Arg.NotNull(apiVersion, nameof(apiVersion));
            Contract.Ensures(Contract.Result <ODataRoute>() != null);

            var routeConventions = EnsureConventions(routingConventions.ToList());
            var routes           = configuration.Routes;

            if (!IsNullOrEmpty(routePrefix))
            {
                routePrefix = routePrefix.TrimEnd('/');
            }

            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                pathHandler.UrlKeyDelimiter = configuration.GetUrlKeyDelimiter();
            }

            model.SetAnnotationValue(model, new ApiVersionAnnotation(apiVersion));
            routeConventions.Insert(0, new VersionedAttributeRoutingConvention(routeName, configuration, apiVersion));

            var rootContainer = configuration.CreateODataRootContainer(
                routeName,
                builder => builder.AddService(Singleton, typeof(IEdmModel), sp => model)
                .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler)
                .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), sp => routeConventions.ToArray())
                .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler)
                .AddService(Singleton, typeof(HttpMessageHandler), sp => defaultHandler));

            rootContainer.InitializeAttributeRouting();

            var routeConstraint = new VersionedODataPathRouteConstraint(routeName, apiVersion);
            var route           = default(ODataRoute);

            if (defaultHandler != null)
            {
                route = new ODataRoute(routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: defaultHandler);
            }
            else
            {
                if (batchHandler != null)
                {
                    batchHandler.ODataRouteName = routeName;
                    var batchTemplate = IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch;
                    routes.MapHttpBatchRoute(routeName + nameof(ODataRouteConstants.Batch), batchTemplate, batchHandler);
                }

                route = new ODataRoute(routePrefix, routeConstraint);
            }

            routes.Add(routeName, route);
            AddApiVersionConstraintIfNecessary(route);

            var unversionedRouteConstraint = new ODataPathRouteConstraint(routeName);
            var unversionedRoute           = new ODataRoute(routePrefix, new UnversionedODataPathRouteConstraint(unversionedRouteConstraint, apiVersion));

            AddApiVersionConstraintIfNecessary(unversionedRoute);
            routes.Add(routeName + UnversionedRouteSuffix, unversionedRoute);

            return(route);
        }
コード例 #49
0
        /// <summary>
        /// Maps the specified OData route and the OData route attributes.
        /// </summary>
        /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        /// <returns>The input <see cref="IEndpointRouteBuilder"/>.</returns>
        public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder,
                                                          string routeName,
                                                          string routePrefix,
                                                          Action <IContainerBuilder> configureAction)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (routeName == null)
            {
                throw new ArgumentNullException(nameof(routeName));
            }

            // Build and configure the root container.
            IServiceProvider serviceProvider = builder.ServiceProvider;

            IPerRouteContainer perRouteContainer = serviceProvider.GetRequiredService <IPerRouteContainer>();

            if (perRouteContainer == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, SRResources.MissingODataServices, nameof(IPerRouteContainer)));
            }

            // Make sure the MetadataController is registered with the ApplicationPartManager.
            ApplicationPartManager applicationPartManager = serviceProvider.GetRequiredService <ApplicationPartManager>();

            applicationPartManager.ApplicationParts.Add(new AssemblyPart(typeof(MetadataController).Assembly));

            // Create an service provider for this route. Add the default services to the custom configuration actions.
            Action <IContainerBuilder> builderAction = ConfigureDefaultServices(builder, configureAction);

            IServiceProvider subServiceProvider = perRouteContainer.CreateODataRootContainer(routeName, builderAction);

            // Resolve the path handler and set URI resolver to it.
            IODataPathHandler pathHandler = subServiceProvider.GetRequiredService <IODataPathHandler>();

            // If settings is not on local, use the global configuration settings.
            ODataOptions options = serviceProvider.GetRequiredService <ODataOptions>();

            //if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            //{
            //    pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter;
            //}

            // Resolve HTTP handler, create the OData route and register it.
            routePrefix = RemoveTrailingSlash(routePrefix);

            // If a batch handler is present, register the route with the batch path mapper. This will be used
            // by the batching middleware to handle the batch request. Batching still requires the injection
            // of the batching middleware via UseODataBatching().
            ODataBatchHandler batchHandler = subServiceProvider.GetService <ODataBatchHandler>();

            if (batchHandler != null)
            {
                // TODO: for the $batch, need refactor/test it for more.
                batchHandler.ODataRouteName = routeName;

                string batchPath = String.IsNullOrEmpty(routePrefix)
                    ? '/' + ODataRouteConstants.Batch
                    : '/' + routePrefix + '/' + ODataRouteConstants.Batch;

                ODataBatchPathMapping batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>();
                batchMapping.IsEndpointRouting = true;
                batchMapping.AddRoute(routeName, batchPath);
            }

            builder.MapDynamicControllerRoute <ODataEndpointRouteValueTransformer>(
                ODataEndpointPattern.CreateODataEndpointPattern(routeName, routePrefix));

            perRouteContainer.AddRoute(routeName, routePrefix);

            return(builder);
        }
コード例 #50
0
 /// <summary>
 /// Maps the specified OData route.
 /// </summary>
 /// <param name="configuration">The server configuration.</param>
 /// <param name="routeName">The name of the route to map.</param>
 /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
 /// <param name="model">The EDM model to use for parsing OData paths.</param>
 /// <param name="pathHandler">The <see cref="IODataPathHandler"/> to use for parsing the OData path.</param>
 /// <param name="routingConventions">
 /// The OData routing conventions to use for controller and action selection.
 /// </param>
 /// <returns>The added <see cref="ODataRoute"/>.</returns>
 public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
                                               string routePrefix, IEdmModel model, IODataPathHandler pathHandler,
                                               IEnumerable <IODataRoutingConvention> routingConventions)
 {
     return(MapODataServiceRoute(configuration, routeName, routePrefix, model, pathHandler, routingConventions,
                                 batchHandler: null));
 }
コード例 #51
0
 public static string ODataLink(this UrlHelper urlHelper, string routeName, IODataPathHandler pathHandler,
     IList<ODataPathSegment> segments)
 {
     return UrlHelperExtensions.CreateODataLink(urlHelper, routeName, pathHandler, segments);
 }
コード例 #52
0
        /// <summary>
        /// Maps the specified OData route and the OData route attributes.
        /// </summary>
        /// <param name="builder">The <see cref="IRouteBuilder"/> to add the route to.</param>
        /// <param name="routeName">The name of the route to map.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        /// <returns>The added <see cref="ODataRoute"/>.</returns>
        public static ODataRoute MapODataServiceRoute(this IRouteBuilder builder, string routeName,
                                                      string routePrefix, Action <IContainerBuilder> configureAction)
        {
            if (builder == null)
            {
                throw Error.ArgumentNull("builder");
            }

            if (routeName == null)
            {
                throw Error.ArgumentNull("routeName");
            }

            // Build and configure the root container.
            IPerRouteContainer perRouteContainer = builder.ServiceProvider.GetRequiredService <IPerRouteContainer>();

            if (perRouteContainer == null)
            {
                throw Error.InvalidOperation(SRResources.MissingODataServices, nameof(IPerRouteContainer));
            }

            // Create an service provider for this route. Add the default services to the custom configuration actions.
            Action <IContainerBuilder> builderAction   = ConfigureDefaultServices(builder, configureAction);
            IServiceProvider           serviceProvider = perRouteContainer.CreateODataRootContainer(routeName, builderAction);

            // Make sure the MetadataController is registered with the ApplicationPartManager.
            ApplicationPartManager applicationPartManager = builder.ServiceProvider.GetRequiredService <ApplicationPartManager>();

            applicationPartManager.ApplicationParts.Add(new AssemblyPart(typeof(MetadataController).Assembly));

            // Resolve the path handler and set URI resolver to it.
            IODataPathHandler pathHandler = serviceProvider.GetRequiredService <IODataPathHandler>();

            // If settings is not on local, use the global configuration settings.
            ODataOptions options = builder.ServiceProvider.GetRequiredService <ODataOptions>();

            if (pathHandler != null && pathHandler.UrlKeyDelimiter == null)
            {
                pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter;
            }

            // Resolve some required services and create the route constraint.
            ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(routeName);

            // Get constraint resolver.
            IInlineConstraintResolver inlineConstraintResolver = builder
                                                                 .ServiceProvider
                                                                 .GetRequiredService <IInlineConstraintResolver>();

            // Resolve HTTP handler, create the OData route and register it.
            ODataRoute route = null;

            routePrefix = RemoveTrailingSlash(routePrefix);

            IRouter customRouter = serviceProvider.GetService <IRouter>();

            route = new ODataRoute(
                customRouter != null ? customRouter : builder.DefaultHandler,
                routeName,
                routePrefix,
                routeConstraint,
                inlineConstraintResolver);

            // If a batch handler is present, register the route with the batch path mapper. This will be used
            // by the batching middleware to handle the batch request. Batching still requires the injection
            // of the batching middleware via UseODataBatching().
            ODataBatchHandler batchHandler = serviceProvider.GetService <ODataBatchHandler>();

            if (batchHandler != null)
            {
                batchHandler.ODataRoute     = route;
                batchHandler.ODataRouteName = routeName;

                string batchPath = String.IsNullOrEmpty(routePrefix)
                    ? '/' + ODataRouteConstants.Batch
                    : '/' + routePrefix + '/' + ODataRouteConstants.Batch;

                ODataBatchPathMapping batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>();
                batchMapping.AddRoute(routeName, batchPath);
            }

            builder.Routes.Add(route);
            return(route);
        }