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

            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);
        }
Esempio n. 2
0
        static void AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(
            this IRouteBuilder builder,
            string routeName,
            string routePrefix,
            ApiVersion apiVersion,
            IInlineConstraintResolver inlineConstraintResolver)
        {
            Contract.Requires(builder != null);
            Contract.Requires(!IsNullOrEmpty(routeName));
            Contract.Requires(apiVersion != null);
            Contract.Requires(inlineConstraintResolver != null);

            routeName += UnversionedRouteSuffix;

            var innerConstraint = new ODataPathRouteConstraint(routeName);
            var constraint      = new UnversionedODataPathRouteConstraint(innerConstraint, apiVersion);
            var route           = new ODataRoute(builder.DefaultHandler, routeName, routePrefix, constraint, inlineConstraintResolver);

            builder.Routes.Add(route);
        }
Esempio n. 3
0
        public ODataRoute MapCustomODataServiceRoute(HttpRouteCollection routes, string routeName, string routePrefix)
        {
            var routingConventions = ODataRoutingConventions.CreateDefault();

            routingConventions.Insert(0, new MatchAllRoutingConvention(this.logger));

            routePrefix = RemoveTrailingSlash(routePrefix);

            // TODO: batches
            //if (EnableBatchSupport)
            //{
            //	MappHttpBatchRoute(routes, new DefaultODataBatchHandler(), routeName, routePrefix);
            //}

            var pathHandler     = new LoggingPathHandler(this.logger);
            var routeConstraint = new ODataPathRouteConstraint(pathHandler, this.oDataRepository.GetModel(), routeName, routingConventions);
            var odataRoute      = new ODataRoute(routePrefix, routeConstraint);

            routes.Add(routeName, odataRoute);
            return(odataRoute);
        }
        /// <summary>
        /// Enables OData support by adding an OData route and enabling OData controller and action selection, querying, and formatter support for OData.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="model">The EDM model to use for the service.</param>
        /// <param name="routePrefix">The prefix to add to the OData route's path template.</param>
        public static void EnableOData(this HttpConfiguration configuration, IEdmModel model, string routePrefix)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

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

            // Querying
            configuration.SetEdmModel(model);
            configuration.EnableQuerySupport();

            // Routing
            string routeTemplate = String.IsNullOrEmpty(routePrefix) ?
                                   ODataRouteConstants.ODataPathTemplate :
                                   routePrefix + "/" + ODataRouteConstants.ODataPathTemplate;
            IODataPathHandler    pathHandler     = configuration.GetODataPathHandler() ?? new DefaultODataPathHandler(model);
            IHttpRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler);

            configuration.Routes.MapHttpRoute(ODataRouteConstants.RouteName, routeTemplate, null, new HttpRouteValueDictionary()
            {
                { ODataRouteConstants.ConstraintName, routeConstraint }
            });

            IEnumerable <IODataRoutingConvention> routingConventions = configuration.GetODataRoutingConventions();
            IHttpControllerSelector controllerSelector = new ODataControllerSelector(routingConventions, configuration.Services.GetHttpControllerSelector());
            IHttpActionSelector     actionSelector     = new ODataActionSelector(routingConventions, configuration.Services.GetActionSelector());

            configuration.Services.Replace(typeof(IHttpControllerSelector), controllerSelector);
            configuration.Services.Replace(typeof(IHttpActionSelector), actionSelector);

            // Formatter
            configuration.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(model));
        }
Esempio n. 5
0
        private static ODataPathRouteConstraint MakeVersionedODataRouteConstraint(
            ODataPathRouteConstraint routeConstraint,
            IODataPathHandler pathHandler,
            IList<IODataRoutingConvention> routeConventions,
            IEdmModel model,
            ref string versionedRouteName )
        {
            Contract.Requires( routeConstraint != null );
            Contract.Requires( pathHandler != null );
            Contract.Requires( routeConventions != null );
            Contract.Requires( model != null );
            Contract.Requires( !IsNullOrEmpty( versionedRouteName ) );
            Contract.Ensures( Contract.Result<ODataPathRouteConstraint>() != null );

            var apiVersion = model.GetAnnotationValue<ApiVersionAnnotation>( model )?.ApiVersion;

            if ( apiVersion == null )
            {
                return routeConstraint;
            }

            versionedRouteName += "-" + apiVersion.ToString();
            return new VersionedODataPathRouteConstraint( pathHandler, model, versionedRouteName, routeConventions.ToArray(), apiVersion );
        }
        /// <summary>
        /// Creates a set of transformed route values that will be used to select an action.
        /// </summary>
        /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
        /// <param name="values">The route values associated with the current match.</param>
        /// <returns>A task which asynchronously returns a set of route values.</returns>
        public override ValueTask <RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            if (httpContext == null)
            {
                throw Error.ArgumentNull(nameof(httpContext));
            }

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

            if (httpContext.ODataFeature().Path != null)
            {
                // Noted: if there's a route mapping with ODataPrefix == null,
                // for example: router.MapODataRoute(routeName: "odata", routePrefix: null, ...)
                // This route will match all requests.
                // Therefore, this route will be a candidate and its tranformer will be called.
                // So, we use the ODataPath setting to verify whether the request is transformed or not.
                // Maybe we have a better solution later.
                return(new ValueTask <RouteValueDictionary>(result: null));
            }

            (string routeName, object oDataPathValue) = values.GetODataRouteInfo();
            if (routeName != null)
            {
                HttpRequest request   = httpContext.Request;
                string      oDataPath = oDataPathValue as string;
                // Create request container
                request.CreateRequestContainer(routeName);

                // Check whether the request is a POST targeted at a resource path ending in /$query
                if (request.IsQueryRequest(oDataPath))
                {
                    request.TransformQueryRequest();

                    oDataPath = oDataPath.Substring(0, oDataPath.LastIndexOf('/' + ODataRouteConstants.QuerySegment, StringComparison.OrdinalIgnoreCase));
                    values[ODataRouteConstants.ODataPath] = oDataPath;
                }

                // We need to call Uri.GetLeftPart(), which returns an encoded Url.
                // The ODL parser does not like raw values.
                Uri    requestUri      = new Uri(request.GetEncodedUrl());
                string requestLeftPart = requestUri.GetLeftPart(UriPartial.Path);
                string queryString     = request.QueryString.HasValue ? request.QueryString.ToString() : null;

                // Call ODL to parse the Request URI.
                ODataPath path = ODataPathRouteConstraint.GetODataPath(oDataPath, requestLeftPart, queryString, () => request.GetRequestContainer());
                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.Path              = path;
                    odataFeature.RouteName         = routeName;
                    odataFeature.IsEndpointRouting = true; // mark as Endpoint routing

                    // Noted: we inject the ActionSelector and use it to select the best OData action.
                    // In .NET 5 or later, this maybe change.
                    RouteContext routeContext     = new RouteContext(httpContext);
                    var          condidates       = _selector.SelectCandidates(routeContext);
                    var          actionDescriptor = _selector.SelectBestCandidate(routeContext, condidates);
                    ControllerActionDescriptor controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
                    if (controllerActionDescriptor != null)
                    {
                        RouteValueDictionary newValues = new RouteValueDictionary();
                        foreach (var item in values)
                        {
                            newValues.Add(item.Key, item.Value);
                        }

                        foreach (var item in routeContext.RouteData.Values)
                        {
                            newValues[item.Key] = item.Value;
                        }

                        newValues["controller"] = controllerActionDescriptor.ControllerName;
                        newValues["action"]     = controllerActionDescriptor.ActionName;
                        newValues["odataPath"]  = oDataPathValue;

                        // Noted, here's a working around for mulitiple actions in same controller.
                        // For example, we have two "Get" methods in same controller, in order to help "EndpointSelector"
                        // to select the correct Endpoint, we save the ActionDescriptor value into ODataFeature.
                        odataFeature.ActionDescriptor = controllerActionDescriptor;
                        // Add handler to handle options calls. The routing criteria has been patched to allow endpoint discovery using the correct cors headers
                        if (request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase))
                        {
                            var metadata = actionDescriptor.EndpointMetadata;
                            // For option request can set this as the action will be handled by the cors middleware
                            var metadataCollection = metadata?.Any() == true
                                ? new EndpointMetadataCollection(metadata)
                                : EndpointMetadataCollection.Empty;
                            // This workaround allows the default cors middleware to read the annotations if the user has them enabling fine-grained cors access control with endpoints
                            var endpoint = new Endpoint(null, metadataCollection, controllerActionDescriptor.ActionName);
                            httpContext.SetEndpoint(endpoint);
                        }

                        return(new ValueTask <RouteValueDictionary>(newValues));
                    }
                }
                else
                {
                    // The request doesn't match this route so dispose the request container.
                    request.DeleteRequestContainer(true);
                }
            }

            return(new ValueTask <RouteValueDictionary>(result: null));
        }
        /// <summary>
        /// Creates a set of transformed route values that will be used to select an action.
        /// </summary>
        /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
        /// <param name="values">The route values associated with the current match.</param>
        /// <returns>A task which asynchronously returns a set of route values.</returns>
        public override ValueTask <RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
        {
            if (httpContext == null)
            {
                throw Error.ArgumentNull(nameof(httpContext));
            }

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

            if (httpContext.ODataFeature().Path != null)
            {
                // Noted: if there's a route mapping with ODataPrefix == null,
                // for example: router.MapODataRoute(routeName: "odata", routePrefix: null, ...)
                // This route will match all requests.
                // Therefore, this route will be a candidate and its tranformer will be called.
                // So, we use the ODataPath setting to verify whether the request is transformed or not.
                // Maybe we have a better solution later.
                return(new ValueTask <RouteValueDictionary>(result: null));
            }

            (string routeName, object oDataPathValue) = values.GetODataRouteInfo();
            if (routeName != null)
            {
                HttpRequest request = httpContext.Request;

                // We need to call Uri.GetLeftPart(), which returns an encoded Url.
                // The ODL parser does not like raw values.
                Uri    requestUri      = new Uri(request.GetEncodedUrl());
                string requestLeftPart = requestUri.GetLeftPart(UriPartial.Path);
                string queryString     = request.QueryString.HasValue ? request.QueryString.ToString() : null;

                // Call ODL to parse the Request URI.
                ODataPath path = ODataPathRouteConstraint.GetODataPath(oDataPathValue as string, requestLeftPart, queryString, () => request.CreateRequestContainer(routeName));
                if (path != null)
                {
                    // Set all the properties we need for routing, querying, formatting
                    IODataFeature odataFeature = httpContext.ODataFeature();
                    odataFeature.Path              = path;
                    odataFeature.RouteName         = routeName;
                    odataFeature.IsEndpointRouting = true; // mark as Endpoint routing

                    // Noted: we inject the ActionSelector and use it to select the best OData action.
                    // In .NET 5 or later, this maybe change.
                    RouteContext routeContext     = new RouteContext(httpContext);
                    var          condidates       = _selector.SelectCandidates(routeContext);
                    var          actionDescriptor = _selector.SelectBestCandidate(routeContext, condidates);
                    ControllerActionDescriptor controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
                    if (controllerActionDescriptor != null)
                    {
                        RouteValueDictionary newValues = new RouteValueDictionary();
                        foreach (var item in values)
                        {
                            newValues.Add(item.Key, item.Value);
                        }

                        foreach (var item in routeContext.RouteData.Values)
                        {
                            newValues[item.Key] = item.Value;
                        }

                        newValues["controller"] = controllerActionDescriptor.ControllerName;
                        newValues["action"]     = controllerActionDescriptor.ActionName;
                        newValues["odataPath"]  = oDataPathValue;

                        // Noted, here's a working around for mulitiple actions in same controller.
                        // For example, we have two "Get" methods in same controller, in order to help "EndpointSelector"
                        // to select the correct Endpoint, we save the ActionDescriptor value into ODataFeature.
                        odataFeature.ActionDescriptor = controllerActionDescriptor;

                        return(new ValueTask <RouteValueDictionary>(newValues));
                    }
                }
                else
                {
                    // The request doesn't match this route so dispose the request container.
                    request.DeleteRequestContainer(true);
                }
            }

            return(new ValueTask <RouteValueDictionary>(result: null));
        }
 public CustomODataRoute(IRouter target, string routeName, string routePrefix, ODataPathRouteConstraint routeConstraint, IInlineConstraintResolver resolver)
     : base(target, routeName, routePrefix, routeConstraint, resolver)
 {
 }
        /// <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);
        }
Esempio n. 10
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);
        }
Esempio n. 11
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="apiVersion">The <see cref="ApiVersion">API version</see> associated with the model.</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 MapVersionedODataRoute(this HttpConfiguration configuration, string routeName, string routePrefix, ApiVersion apiVersion, Action <IContainerBuilder> configureAction)
        {
            Arg.NotNull(configuration, nameof(configuration));
            Arg.NotNull(apiVersion, nameof(apiVersion));
            Contract.Ensures(Contract.Result <ODataRoute>() != null);

            object ConfigureRoutingConventions(IServiceProvider serviceProvider)
            {
                var model = serviceProvider.GetRequiredService <IEdmModel>();
                var routingConventions = EnsureConventions(ODataRoutingConventions.CreateDefault());

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

                return(routingConventions.ToArray());
            }

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

            var rootContainer = configuration.CreateODataRootContainer(
                routeName,
                builder =>
            {
                builder.AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), ConfigureRoutingConventions);
                configureAction?.Invoke(builder);
            });
            var pathHandler = rootContainer.GetRequiredService <IODataPathHandler>();

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

            rootContainer.InitializeAttributeRouting();

            var routeConstraint = new VersionedODataPathRouteConstraint(routeName, apiVersion);
            var route           = default(ODataRoute);
            var routes          = configuration.Routes;
            var messageHandler  = rootContainer.GetService <HttpMessageHandler>();

            if (messageHandler != null)
            {
                route = new ODataRoute(
                    routePrefix,
                    routeConstraint,
                    defaults: null,
                    constraints: null,
                    dataTokens: null,
                    handler: messageHandler);
            }
            else
            {
                var batchHandler = rootContainer.GetService <ODataBatchHandler>();

                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);
            configuration.Routes.Add(routeName + UnversionedRouteSuffix, unversionedRoute);

            return(route);
        }
Esempio n. 12
0
        /// <summary>
        /// Test method to call constraint.Match using the proper arguments for each platform.
        /// </summary>
        /// <param name="constraint">The constraint object.</param>
        /// <param name="routeRequest">The abstracted request.</param>
        /// <param name="direction">The abstracted route direction.</param>
        /// <returns>Result from constraint.Match,</returns>
        private bool ConstraintMatch(ODataPathRouteConstraint constraint, TestRouteRequest routeRequest, Dictionary <string, object> values, RouteDirection direction)
        {
#if NETCORE
            IRouteBuilder config = RoutingConfigurationFactory.Create();
            if (routeRequest?.PathHandler != null && routeRequest?.Model != null)
            {
                config.MapODataServiceRoute(_routeName, "", builder =>
                                            builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.PathHandler)
                                            .AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.Model));
            }
            else if (routeRequest?.PathHandler != null)
            {
                config.MapODataServiceRoute(_routeName, "", builder =>
                                            builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.PathHandler));
            }
            else if (routeRequest?.Model != null)
            {
                config.MapODataServiceRoute(_routeName, "", builder =>
                                            builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.Model));
            }
            else
            {
                config.MapODataServiceRoute(_routeName, "", builder => { });
            }

            HttpRequest request = (routeRequest != null)
                ? RequestFactory.Create(routeRequest.Method, routeRequest.Uri, config, _routeName)
                : RequestFactory.Create();

            // The RequestFactory will create a request container which most tests want but for checking the constraint,
            // we don't want a request container before the test runs since Match() creates one.
            request.DeleteRequestContainer(true);

            if (routeRequest != null)
            {
                routeRequest.InnerRequest = request;
            }

            AspNetCore.Routing.RouteDirection routeDirection = (direction == RouteDirection.UriResolution)
                ? AspNetCore.Routing.RouteDirection.IncomingRequest
                : AspNetCore.Routing.RouteDirection.UrlGeneration;

            RouteValueDictionary routeValues = new RouteValueDictionary(values);

            return(constraint.Match(request.HttpContext, null, null, routeValues, routeDirection));
#else
            HttpRequestMessage request = (routeRequest != null)
                ? new HttpRequestMessage(routeRequest.Method, routeRequest.Uri)
                : new HttpRequestMessage();

            var httpRouteCollection = new HttpRouteCollection
            {
                { _routeName, new HttpRoute() },
            };

            var configuration = new HttpConfiguration(httpRouteCollection);
            if (routeRequest != null && routeRequest.PathHandler != null && routeRequest.Model != null)
            {
                configuration.CreateODataRootContainer(_routeName, builder =>
                                                       builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.PathHandler)
                                                       .AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.Model));
            }
            else if (routeRequest != null && routeRequest.PathHandler != null)
            {
                configuration.CreateODataRootContainer(_routeName, builder =>
                                                       builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.PathHandler));
            }
            else if (routeRequest != null && routeRequest.Model != null)
            {
                configuration.CreateODataRootContainer(_routeName, builder =>
                                                       builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => routeRequest.Model));
            }
            else
            {
                PerRouteContainer perRouteContainer = configuration.GetPerRouteContainer() as PerRouteContainer;
                perRouteContainer.SetODataRootContainer(_routeName, _rootContainer);
            }

            request.SetConfiguration(configuration);
            if (routeRequest != null)
            {
                routeRequest.InnerRequest = request;
            }

            HttpRouteDirection routeDirection = (direction == RouteDirection.UriResolution)
                ? HttpRouteDirection.UriResolution
                : HttpRouteDirection.UriGeneration;

            return(constraint.Match(request, null, null, values, routeDirection));
#endif
        }
        /// <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);
        }
Esempio n. 14
0
 public CustomODataRoute(string routePrefix, ODataPathRouteConstraint pathConstraint)
     : base(routePrefix, pathConstraint)
 {
     _canGenerateDirectLink = routePrefix != null && RoutePrefix.IndexOf('{') == -1;
 }
Esempio n. 15
0
 public CustomODataRoute(string routePrefix, ODataPathRouteConstraint pathConstraint)
     : this(routePrefix, pathConstraint, defaults : null, constraints : null, dataTokens : null, handler : null)
 {
 }