示例#1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AttributeRoutingConvention"/> class.
        /// </summary>
        /// <param name="routeName">The name of the route.</param>
        /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to use for figuring out all the controllers to
        /// look for a match.</param>
        /// <param name="pathTemplateHandler">The path template handler to be used for parsing the path templates.</param>
        /// <remarks>
        /// While this function does not use types that are AspNetCore-specific,
        /// the functionality is due to the way assembly resolution is done in AspNet vs AspnetCore.
        /// </remarks>
        public AttributeRoutingConvention(string routeName, IServiceProvider serviceProvider,
                                          IODataPathTemplateHandler pathTemplateHandler = null)
            : this(routeName)
        {
            if (serviceProvider == null)
            {
                throw Error.ArgumentNull("serviceProvider");
            }

            _serviceProvider = serviceProvider;

            if (pathTemplateHandler != null)
            {
                ODataPathTemplateHandler = pathTemplateHandler;
            }
            else
            {
                IPerRouteContainer perRouteContainer = _serviceProvider.GetRequiredService <IPerRouteContainer>();
                if (perRouteContainer == null)
                {
                    throw Error.InvalidOperation(SRResources.MissingODataServices, nameof(IPerRouteContainer));
                }

                IServiceProvider rootContainer = perRouteContainer.GetODataRootContainer(routeName);
                ODataPathTemplateHandler = rootContainer.GetRequiredService <IODataPathTemplateHandler>();
            }
        }
示例#2
0
        /// <summary>
        /// Invoke the middleware.
        /// </summary>
        /// <param name="context">The http context.</param>
        /// <returns>A task that can be awaited.</returns>
        public async Task Invoke(HttpContext context)
        {
            HttpRequest request     = context.Request;
            bool        isPreFlight = HttpMethods.IsOptions(request.Method);

            // Attempt to match the path to a batch route.
            ODataBatchPathMapping batchMapping = context.RequestServices.GetRequiredService <ODataBatchPathMapping>();

            if (!isPreFlight && batchMapping.TryGetRouteName(context, out string routeName))
            {
                // Get the per-route container and retrieve the batch handler.
                IPerRouteContainer perRouteContainer = context.RequestServices.GetRequiredService <IPerRouteContainer>();
                if (perRouteContainer == null)
                {
                    throw Error.InvalidOperation(SRResources.MissingODataServices, nameof(IPerRouteContainer));
                }

                IServiceProvider  rootContainer = perRouteContainer.GetODataRootContainer(routeName);
                ODataBatchHandler batchHandler  = rootContainer.GetRequiredService <ODataBatchHandler>();

                await batchHandler.ProcessBatchAsync(context, next);
            }
            else
            {
                await this.next(context);
            }
        }
示例#3
0
        /// <summary>
        /// Create the per-route container from the configuration for a given route.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="routeName">The route name.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        /// <returns>The per-route container from the configuration</returns>
        internal static IServiceProvider CreateODataRootContainer(this HttpConfiguration configuration,
                                                                  string routeName, Action <IContainerBuilder> configureAction)
        {
            IPerRouteContainer perRouteContainer = configuration.GetPerRouteContainer();

            return(perRouteContainer.CreateODataRootContainer(routeName, ConfigureDefaultServices(configuration, configureAction)));
        }
示例#4
0
        /// <remarks>This signature uses types that are AspNetCore-specific.</remarks>
        private IEnumerable <ODataPathTemplate> GetODataPathTemplates(string prefix, ControllerActionDescriptor controllerAction)
        {
            Contract.Assert(controllerAction != null);

            IEnumerable <ODataRouteAttribute> routeAttributes =
                controllerAction.MethodInfo.GetCustomAttributes <ODataRouteAttribute>(inherit: false);

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

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

            IServiceProvider requestContainer = perRouteContainer.GetODataRootContainer(_routeName);

            string controllerName = controllerAction.ControllerName;
            string actionName     = controllerAction.ActionName;

            return
                (routeAttributes
                 .Where(route => string.IsNullOrEmpty(route.RouteName) || route.RouteName == _routeName)
                 .Select(route => GetODataPathTemplate(prefix, route.PathTemplate, requestContainer, controllerName, actionName))
                 .Where(template => template != null));
        }
示例#5
0
        /// <summary>
        /// Initializes a new instance of the routing configuration class.
        /// </summary>
        /// <returns>A new instance of the routing configuration class.</returns>
        public static HttpRequest Create(IRouteBuilder routeBuilder = null, string routeName = null)
        {
            // Add the options services.
            string useRouteName = (routeName == null) ? "OData" : routeName;

            if (routeBuilder == null)
            {
                routeBuilder = RoutingConfigurationFactory.CreateWithRootContainer(useRouteName);
            }

            // Create a new context and assign the services.
            HttpContext context = new DefaultHttpContext();

            context.RequestServices = routeBuilder.ServiceProvider;

            // Ensure there is route data for the routing tests.
            var routeContext = new RouteContext(context);

            context.Features[typeof(IRoutingFeature)] = new RoutingFeature()
            {
                RouteData = routeContext.RouteData,
            };

            // Assign the route and get the request container, which will initialize
            // the request container if one does not exists.
            context.Request.ODataFeature().RouteName = useRouteName;
            IPerRouteContainer perRouteContainer     = routeBuilder.ServiceProvider.GetRequiredService <IPerRouteContainer>();

            if (!perRouteContainer.HasODataRootContainer(useRouteName))
            {
                Action <IContainerBuilder> builderAction   = ODataRouteBuilderExtensions.ConfigureDefaultServices(routeBuilder, null);
                IServiceProvider           serviceProvider = perRouteContainer.CreateODataRootContainer(useRouteName, builderAction);
            }

            // Add some routing info
            IRouter   defaultRoute = routeBuilder.Routes.FirstOrDefault();
            RouteData routeData    = new RouteData();

            if (defaultRoute != null)
            {
                routeData.Routers.Add(defaultRoute);
            }
            else
            {
                var resolver = routeBuilder.ServiceProvider.GetRequiredService <IInlineConstraintResolver>();
                routeData.Routers.Add(new ODataRoute(routeBuilder.DefaultHandler, useRouteName, null, new ODataPathRouteConstraint(useRouteName), resolver));
            }

            var mockAction = new Mock <ActionDescriptor>();
            ActionDescriptor actionDescriptor = mockAction.Object;

            ActionContext actionContext = new ActionContext(context, routeData, actionDescriptor);

            IActionContextAccessor actionContextAccessor = context.RequestServices.GetRequiredService <IActionContextAccessor>();

            actionContextAccessor.ActionContext = actionContext;

            // Get request and return it.
            return(context.Request);
        }
        /// <inheritdoc/>
        public override string GetPathByAddress <TAddress>(HttpContext httpContext, TAddress address, RouteValueDictionary values, RouteValueDictionary ambientValues = null, PathString?pathBase = null, FragmentString fragment = default, LinkOptions options = null)
        {
            object odataPathValue;

            if (values.TryGetValue("odataPath", out odataPathValue))
            {
                string odataPath = odataPathValue as string;
                if (odataPath != null)
                {
                    IPerRouteContainer perRouteContainer = httpContext.RequestServices.GetRequiredService <IPerRouteContainer>();
                    string             routePrefix       = perRouteContainer.GetRoutePrefix(httpContext.Request.ODataFeature().RouteName);

                    bool canGenerateDirectLink = routePrefix == null || routePrefix.IndexOf('{') == -1;
                    if (!canGenerateDirectLink)
                    {
                        routePrefix = BindPrefixTemplate(routePrefix, values, ambientValues);
                    }
                    string link = CombinePathSegments(routePrefix, odataPath);
                    link = UriEncode(link);
                    return(link);
                }
            }

            return(_innerGenerator.GetPathByAddress(httpContext, address, values, ambientValues, pathBase, fragment, options));
        }
        /// <inheritdoc/>
        public override string GetPathByAddress <TAddress>(HttpContext httpContext, TAddress address, RouteValueDictionary values, RouteValueDictionary ambientValues = null, PathString?pathBase = null, FragmentString fragment = default, LinkOptions options = null)
        {
            object odataPathValue;

            if (values.TryGetValue("odataPath", out odataPathValue))
            {
                string odataPath = odataPathValue as string;
                if (odataPath != null)
                {
                    IPerRouteContainer perRouteContainer = httpContext.RequestServices.GetRequiredService <IPerRouteContainer>();
                    string             routePrefix       = perRouteContainer.GetRoutePrefix(httpContext.Request.ODataFeature().RouteName);

                    bool canGenerateDirectLink = routePrefix == null || routePrefix.IndexOf('{') == -1;
                    if (!canGenerateDirectLink)
                    {
                        routePrefix = BindPrefixTemplate(routePrefix, values, ambientValues);
                    }
                    string link = CombinePathSegments(routePrefix, odataPath);
                    link = UriEncode(link);

                    // A workaround to include the PathBase, a good solution is to use ASP.NET Core provided the APIs
                    // at https://github.com/dotnet/aspnetcore/blob/master/src/Http/Http.Extensions/src/UriHelper.cs#L48
                    // to build the absolute Uri. But, here only needs the "PathBase + Path (without OData path)",
                    HttpRequest request = httpContext.Request;
                    if (request != null && request.PathBase != null && request.PathBase.HasValue)
                    {
                        return(request.PathBase.Value + "/" + link);
                    }

                    return(link);
                }
            }

            return(_innerGenerator.GetPathByAddress(httpContext, address, values, ambientValues, pathBase, fragment, options));
        }
示例#8
0
        private void InitializeConfiguration(Action <IContainerBuilder> action)
        {
            var                        configuration     = RoutingConfigurationFactory.Create();
            string                     routeName         = HttpRouteCollectionExtensions.RouteName;
            IPerRouteContainer         perRouteContainer = configuration.ServiceProvider.GetRequiredService <IPerRouteContainer>();
            Action <IContainerBuilder> builderAction     = ODataRouteBuilderExtensions.ConfigureDefaultServices(configuration, action);

            _rootContainer = perRouteContainer.CreateODataRootContainer(routeName, builderAction);
        }
示例#9
0
        /// <summary>
        /// Enables dependency injection support for HTTP routes.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        public static void EnableDependencyInjection(this HttpConfiguration configuration,
                                                     Action <IContainerBuilder> configureAction)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            if (configuration.Properties.ContainsKey(NonODataRootContainerKey))
            {
                throw Error.InvalidOperation(SRResources.CannotReEnableDependencyInjection);
            }

            // Get the per-route container and create a new non-route container.
            IPerRouteContainer perRouteContainer = GetPerRouteContainer(configuration);

            perRouteContainer.CreateODataRootContainer(null, ConfigureDefaultServices(configuration, configureAction));
        }
示例#10
0
        /// <summary>
        /// Create a scoped request.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="routeName">The route name.</param>
        /// <returns></returns>
        private static IServiceScope CreateRequestScope(this HttpRequest request, string routeName)
        {
            IPerRouteContainer perRouteContainer = request.HttpContext.RequestServices.GetRequiredService <IPerRouteContainer>();

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

            IServiceProvider rootContainer = perRouteContainer.GetODataRootContainer(routeName);
            IServiceScope    scope         = rootContainer.GetRequiredService <IServiceScopeFactory>().CreateScope();

            // Bind scoping request into the OData container.
            if (!string.IsNullOrEmpty(routeName))
            {
                scope.ServiceProvider.GetRequiredService <HttpRequestScope>().HttpRequest = request;
            }

            return(scope);
        }
示例#11
0
        /// <summary>
        /// Initializes a new instance of the routing configuration class.
        /// </summary>
        /// <returns>A new instance of the routing configuration class.</returns>
        public static IRouteBuilder CreateWithRootContainer(string routeName, Action <IContainerBuilder> configureAction = null)
        {
            IRouteBuilder builder = Create();

            if (!string.IsNullOrEmpty(routeName))
            {
                // Build and configure the root container.
                IPerRouteContainer perRouteContainer = builder.ServiceProvider.GetRequiredService <IPerRouteContainer>();
                if (perRouteContainer == null)
                {
                    throw Error.ArgumentNull("routeName");
                }

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

            return(builder);
        }
        /// <summary>
        /// Enables dependency injection support for HTTP routes.
        /// </summary>
        /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the container to.</param>
        /// <param name="configureAction">The configuring action to add the services to the root container.</param>
        public static void EnableDependencyInjection(this IEndpointRouteBuilder builder,
                                                     Action <IContainerBuilder> configureAction)
        {
            if (builder == null)
            {
                throw Error.ArgumentNull("builder");
            }

            IPerRouteContainer perRouteContainer = builder.ServiceProvider.GetRequiredService <IPerRouteContainer>();

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

            if (perRouteContainer.HasODataRootContainer(null))
            {
                throw Error.InvalidOperation(SRResources.CannotReEnableDependencyInjection);
            }

            // Get the per-route container and create a new non-route container.
            perRouteContainer.CreateODataRootContainer(null, ConfigureDefaultServices(builder, configureAction));
        }
        /// <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 Error.ArgumentNull("builder");
            }

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

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

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

            if (perRouteContainer == null)
            {
                throw Error.InvalidOperation(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, i need more time to refactor/test it.
                // 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.MapDynamicControllerRoute <ODataEndpointRouteValueTransformer>(
                ODataEndpointPattern.CreateODataEndpointPattern(routeName, routePrefix));

            perRouteContainer.AddRoute(routeName, routePrefix);

            return(builder);
        }
示例#14
0
        private IServiceProvider GetServiceProvider(IRouteBuilder routeBuilder, string routeName)
        {
            IPerRouteContainer perRouteContainer = routeBuilder.ServiceProvider.GetRequiredService <IPerRouteContainer>();

            return(perRouteContainer.GetODataRootContainer(routeName));
        }
示例#15
0
        /// <summary>
        /// Get the OData root container for a given route.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="routeName">The route name.</param>
        /// <returns>The OData root container for a given route.</returns>
        internal static IServiceProvider GetODataRootContainer(this HttpConfiguration configuration, string routeName)
        {
            IPerRouteContainer perRouteContainer = GetPerRouteContainer(configuration);

            return(perRouteContainer.GetODataRootContainer(routeName));
        }