/// <summary> /// Initializes a new instance of the <see cref="AttributeRoutingConvention"/> class. /// </summary> /// <param name="routeName">The name of the route.</param> /// <param name="configuration">The <see cref="HttpConfiguration"/> 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> public AttributeRoutingConvention(string routeName, HttpConfiguration configuration, IODataPathTemplateHandler pathTemplateHandler) : this(routeName, pathTemplateHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } IODataPathHandler pathHandler = pathTemplateHandler as 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; } Action <HttpConfiguration> oldInitializer = configuration.Initializer; bool initialized = false; configuration.Initializer = (config) => { if (!initialized) { initialized = true; oldInitializer(config); IHttpControllerSelector controllerSelector = config.Services.GetHttpControllerSelector(); _attributeMappings = BuildAttributeMappings(controllerSelector.GetControllerMapping().Values); } }; }
/// <summary> /// Constructor. /// </summary> /// <param name="serviceBaseUri">The base URI of the service. This will be used as the base URI for all entity containers.</param> /// <param name="urlKeyDelimiter">Key delimiter used in url.</param> internal ODataConventionalUriBuilder(Uri serviceBaseUri, ODataUrlKeyDelimiter urlKeyDelimiter) { Debug.Assert(serviceBaseUri != null && serviceBaseUri.IsAbsoluteUri, "serviceBaseUri != null && serviceBaseUri.IsAbsoluteUri"); Debug.Assert(urlKeyDelimiter != null, "urlKeyDelimiter != null"); this.serviceBaseUri = serviceBaseUri; this.keySerializer = KeySerializer.Create(urlKeyDelimiter.EnableKeyAsSegment); }
public static Uri UriBuilder(Uri queryUri, ODataUrlKeyDelimiter urlKeyDelimiter, ODataUriParserSettings settings) { ODataUriParser odataUriParser = new ODataUriParser(HardCodedTestModel.TestModel, ServiceRoot, queryUri); odataUriParser.UrlKeyDelimiter = urlKeyDelimiter; ODataUri odataUri = odataUriParser.ParseUri(); return(odataUri.BuildUri(urlKeyDelimiter)); }
/// <summary> /// Set the UrlKeyDelimiter in DefaultODataPathHandler. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="urlKeyDelimiter">The <see cref="ODataUrlKeyDelimiter"/></param> public static void SetUrlKeyDelimiter(this HttpConfiguration configuration, ODataUrlKeyDelimiter urlKeyDelimiter) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } configuration.Properties[UrlKeyDelimiterKey] = urlKeyDelimiter; }
/// <summary> /// Set the UrlKeyDelimiter in DefaultODataPathHandler. /// </summary> /// <param name="builder">The <see cref="IRouteBuilder"/>.</param> /// <param name="urlKeyDelimiter">The <see cref="ODataUrlKeyDelimiter"/></param> public static IRouteBuilder SetUrlKeyDelimiter(this IRouteBuilder builder, ODataUrlKeyDelimiter urlKeyDelimiter) { if (builder == null) { throw Error.ArgumentNull("builder"); } if (urlKeyDelimiter == null) { throw Error.ArgumentNull("urlKeyDelimiter"); } ODataOptions defaultOptions = builder.GetDefaultODataOptions(); defaultOptions.UrlKeyDelimiter = urlKeyDelimiter; return(builder); }
private static Uri GenerateQueryFromExpandedItem(ODataSerializerContext writeContext, Uri navigationLink) { IWebApiUrlHelper urlHelper = writeContext.InternalUrlHelper; if (urlHelper == null) { return(navigationLink); } string serviceRoot = urlHelper.CreateODataLink( writeContext.InternalRequest.Context.RouteName, writeContext.InternalRequest.PathHandler, new List <ODataPathSegment>()); Uri serviceRootUri = new Uri(serviceRoot); ODataUriParser parser = new ODataUriParser(writeContext.Model, serviceRootUri, navigationLink); ODataUri newUri = parser.ParseUri(); newUri.SelectAndExpand = writeContext.SelectExpandClause; if (writeContext.CurrentExpandedSelectItem != null) { newUri.OrderBy = writeContext.CurrentExpandedSelectItem.OrderByOption; newUri.Filter = writeContext.CurrentExpandedSelectItem.FilterOption; newUri.Skip = writeContext.CurrentExpandedSelectItem.SkipOption; newUri.Top = writeContext.CurrentExpandedSelectItem.TopOption; if (writeContext.CurrentExpandedSelectItem.CountOption != null) { if (writeContext.CurrentExpandedSelectItem.CountOption.HasValue) { newUri.QueryCount = writeContext.CurrentExpandedSelectItem.CountOption.Value; } } ExpandedNavigationSelectItem expandedNavigationItem = writeContext.CurrentExpandedSelectItem as ExpandedNavigationSelectItem; if (expandedNavigationItem != null) { newUri.SelectAndExpand = expandedNavigationItem.SelectAndExpand; } } ODataUrlKeyDelimiter keyDelimiter = writeContext.InternalRequest.Options.UrlKeyDelimiter == ODataUrlKeyDelimiter.Slash ? ODataUrlKeyDelimiter.Slash : ODataUrlKeyDelimiter.Parentheses; return(newUri.BuildUri(keyDelimiter)); }
/// <summary> /// Initializes a new instance of <see cref="ODataUriParserConfiguration"/>. /// </summary> /// <param name="model">Model to use for metadata binding.</param> /// <param name="container">The optional dependency injection container to get related services for URI parsing.</param> /// <exception cref="System.ArgumentNullException">Throws if input model is null.</exception> /// <exception cref="ArgumentException">Throws if the input serviceRoot is not an AbsoluteUri</exception> public ODataUriParserConfiguration(IEdmModel model, IServiceProvider container) { ExceptionUtils.CheckArgumentNotNull(model, "model"); this.Model = model; this.Container = container; this.Resolver = ODataUriResolver.GetUriResolver(container); this.urlKeyDelimiter = ODataUrlKeyDelimiter.GetODataUrlKeyDelimiter(container); if (this.Container == null) { this.Settings = new ODataUriParserSettings(); } else { this.Settings = this.Container.GetRequiredService <ODataUriParserSettings>(); } this.EnableUriTemplateParsing = false; }
private static Uri GenerateQueryFromExpandedItem(ODataSerializerContext writeContext, Uri navigationLink) { string serviceRoot = writeContext.Request.CreateODataLink(new List <ODataPathSegment>()); Uri serviceRootUri = new Uri(serviceRoot); ODataUriParser parser = new ODataUriParser(writeContext.Model, serviceRootUri, navigationLink); ODataUri newUri = parser.ParseUri(); newUri.SelectAndExpand = writeContext.SelectExpandClause; if (writeContext.CurrentExpandedSelectItem != null) { newUri.OrderBy = writeContext.CurrentExpandedSelectItem.OrderByOption; newUri.Filter = writeContext.CurrentExpandedSelectItem.FilterOption; newUri.Skip = writeContext.CurrentExpandedSelectItem.SkipOption; newUri.Top = writeContext.CurrentExpandedSelectItem.TopOption; if (writeContext.CurrentExpandedSelectItem.CountOption != null) { if (writeContext.CurrentExpandedSelectItem.CountOption.HasValue) { newUri.QueryCount = writeContext.CurrentExpandedSelectItem.CountOption.Value; } } ExpandedNavigationSelectItem expandedNavigationItem = writeContext.CurrentExpandedSelectItem as ExpandedNavigationSelectItem; if (expandedNavigationItem != null) { newUri.SelectAndExpand = expandedNavigationItem.SelectAndExpand; } } ODataUrlKeyDelimiter keyDelimiter = ODataUrlKeyDelimiter.Parentheses; ODataOptions options = writeContext.Request.HttpContext.RequestServices.GetRequiredService <IOptions <ODataOptions> >().Value; if (options != null) { keyDelimiter = options.UrlKeyDelimiter; } return(newUri.BuildUri(keyDelimiter)); }
/// <summary> /// Sets the <see cref="ODataUrlKeyDelimiter"/> to use while parsing, specifically whether to recognize keys as segments or not. /// </summary> /// <param name="keyDelimiter">The key demimiter.</param> /// <returns>The calling itself.</returns> public ODataOptions SetUrlKeyDelimiter(ODataUrlKeyDelimiter keyDelimiter) { UrlKeyDelimiter = keyDelimiter; return(this); }
// Slash became the default 4/18/2018 // REF: https://github.com/OData/WebApi/pull/1393 static ODataUrlKeyDelimiter UrlKeyDelimiterOrDefault(ODataUrlKeyDelimiter urlKeyDelimiter) => urlKeyDelimiter ?? Slash;
private ODataUriParser ParseDynamicPathSegmentFunc_ReturnDynamicPathSegment_WithCollectionReturnType(Uri fullUri, out ODataPath odataPath, ODataUrlKeyDelimiter uriConventions = null) { var container = ContainerBuilderHelper.BuildContainer(builder => builder.AddService <UriPathParser, SingleSegmentUriPathParser>(ServiceLifetime.Scoped)); var uriParser = new ODataUriParser(oneDriveModel, ServiceRoot, fullUri, container); if (uriConventions != null) { uriParser.UrlKeyDelimiter = uriConventions; } var operation = oneDriveModel.SchemaElements.OfType <IEdmOperation>().FirstOrDefault(o => o.Name == "recent"); uriParser.ParseDynamicPathSegmentFunc = (previous, identifier, parenthesisExpression) => { var dynamicPathSeg = new DynamicPathSegment(identifier, operation.ReturnType.Definition, containedItemsNav, false); var segments = new List <ODataPathSegment> { dynamicPathSeg }; if (parenthesisExpression != null) { segments.Add(new KeySegment(dynamicPathSeg, new Dictionary <string, object>() { { "id", parenthesisExpression.Trim('\'') } }, itemType, null)); } return(segments); }; odataPath = uriParser.ParsePath(); return(uriParser); }
private ODataPath ParseDynamicPathSegmentFunc_ReturnDynamicPathSegment_WithCollectionReturnType(Uri fullUri, ODataUrlKeyDelimiter uriConventions = null) { ODataPath odataPath; ParseDynamicPathSegmentFunc_ReturnDynamicPathSegment_WithCollectionReturnType(fullUri, out odataPath, uriConventions); return(odataPath); }
/// <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); }
/// <summary> /// Get the string representation of <see cref="ODataPath"/>. /// mainly translate Query Url path. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="urlKeyDelimiter">Mark whether key is segment</param> /// <returns>The string representation of the Query Url path.</returns> public static string ToResourcePathString(this ODataPath path, ODataUrlKeyDelimiter urlKeyDelimiter) { return(string.Concat(path.WalkWith(new PathSegmentToResourcePathTranslator(urlKeyDelimiter)).ToArray()).TrimStart('/')); }
/// <summary> /// Tries to handle the current segment as a key property value. /// </summary> /// <param name="segmentText">The segment text.</param> /// <param name="previous">The previous segment.</param> /// <param name="previousKeySegment">The parent node's key segment.</param> /// <param name="odataUrlKeyDelimiter">Key delimiter used in url.</param> /// <param name="resolver">The resolver to use.</param> /// <param name="keySegment">The key segment that was created if the segment could be interpreted as a key.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <returns>Whether or not the segment was interpreted as a key.</returns> internal static bool TryHandleSegmentAsKey(string segmentText, ODataPathSegment previous, KeySegment previousKeySegment, ODataUrlKeyDelimiter odataUrlKeyDelimiter, ODataUriResolver resolver, out KeySegment keySegment, bool enableUriTemplateParsing = false) { Debug.Assert(previous != null, "previous != null"); Debug.Assert(odataUrlKeyDelimiter != null, "odataUrlKeyDelimiter != null"); Debug.Assert(resolver != null, "resolver != null"); keySegment = null; // If the current convention does not support keys-as-segments, then this does not apply. if (!odataUrlKeyDelimiter.EnableKeyAsSegment) { return(false); } // Keys only apply to collections, so if the prior segment is already a singleton, do not treat this segment as a key. if (previous.SingleResult) { return(false); } // System segments (ie '$count') are never keys. if (IsSystemSegment(segmentText)) { return(false); } // If the previous type is not an entity collection type // TODO: collapse this and SingleResult. IEdmEntityType targetEntityType; if (previous.TargetEdmType == null || !previous.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType)) { return(false); } // Previously KeyAsSegment only allows single key, but we can also leverage related key finder to auto fill // missed key value from referential constraint information, which would be done in CreateKeySegment. // CreateKeySegment method will check whether key properties are missing after taking in related key values. keySegment = CreateKeySegment(previous, previousKeySegment, SegmentArgumentParser.FromSegment(segmentText, enableUriTemplateParsing), resolver); return(true); }
/// <summary> /// Private constructor since the singleton instance is sufficient. /// </summary> /// <param name="odataUrlKeyDelimiter">Key delimiter used in url.</param> public PathSegmentToResourcePathTranslator(ODataUrlKeyDelimiter odataUrlKeyDelimiter) { Debug.Assert(odataUrlKeyDelimiter != null, "odataUrlKeyDelimiter != null"); this.KeySerializer = KeySerializer.Create(odataUrlKeyDelimiter.EnableKeyAsSegment); }