/// <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>(); } }
/// <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); } }
/// <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))); }
/// <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)); }
/// <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)); }
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); }
/// <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)); }
/// <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); }
/// <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); }
private IServiceProvider GetServiceProvider(IRouteBuilder routeBuilder, string routeName) { IPerRouteContainer perRouteContainer = routeBuilder.ServiceProvider.GetRequiredService <IPerRouteContainer>(); return(perRouteContainer.GetODataRootContainer(routeName)); }
/// <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)); }