Esempio n. 1
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;

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

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

            configuration.SetResolverSettings( pathHandler );
            routeConventions.Insert( 0, null );

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

            foreach ( var model in models )
            {
                var versionedRouteName = routeName;
                var routeConstraint = default( ODataPathRouteConstraint );

                routeConventions[0] = new VersionedAttributeRoutingConvention( model, configuration );
                routeConstraint = new ODataPathRouteConstraint( pathHandler, model, versionedRouteName, routeConventions.ToArray() );
                unversionedConstraints.Add( routeConstraint );
                routeConstraint = MakeVersionedODataRouteConstraint( routeConstraint, pathHandler, routeConventions, model, ref versionedRouteName );

                var route = new ODataRoute( routePrefix, routeConstraint );

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

            AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch( routeName, routePrefix, routes, odataRoutes, unversionedConstraints );

            return odataRoutes;
        }
Esempio n. 2
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);
        }
Esempio n. 3
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);
        }