/// <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); }
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); }
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)); }
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); }
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); }
/// <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); }
/// <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); }
public CustomODataRoute(string routePrefix, ODataPathRouteConstraint pathConstraint) : base(routePrefix, pathConstraint) { _canGenerateDirectLink = routePrefix != null && RoutePrefix.IndexOf('{') == -1; }
public CustomODataRoute(string routePrefix, ODataPathRouteConstraint pathConstraint) : this(routePrefix, pathConstraint, defaults : null, constraints : null, dataTokens : null, handler : null) { }