internal string UriToUriString(Uri uri, bool makeAbsolute) { Uri uri2; if (base.UrlResolver != null) { uri2 = base.UrlResolver.ResolveUrl(base.MessageWriterSettings.BaseUri, uri); if (uri2 != null) { return(UriUtilsCommon.UriToString(uri2)); } } uri2 = uri; if (!uri2.IsAbsoluteUri) { if (makeAbsolute) { if (base.MessageWriterSettings.BaseUri == null) { throw new ODataException(Strings.ODataWriter_RelativeUriUsedWithoutBaseUriSpecified(UriUtilsCommon.UriToString(uri))); } uri2 = UriUtils.UriToAbsoluteUri(base.MessageWriterSettings.BaseUri, uri); } else { uri2 = UriUtils.EnsureEscapedRelativeUri(uri2); } } return(UriUtilsCommon.UriToString(uri2)); }
/// <summary> /// Validates that a string is either a valid absolute URI, or (if it begins with '#') it is a valid URI fragment. /// </summary> /// <param name="metadataDocumentUri">The metadata document uri.</param> /// <param name="propertyName">The property name to validate.</param> internal static void ValidateMetadataReferencePropertyName(Uri metadataDocumentUri, string propertyName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(metadataDocumentUri != null, "metadataDocumentUri != null"); Debug.Assert(metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri.IsAbsoluteUri"); Debug.Assert(!String.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); string uriStringToValidate = propertyName; // If it starts with a '#', validate that the rest of the string is a valid Uri fragment. if (propertyName[0] == JsonLightConstants.MetadataUriFragmentIndicator) { // In order to use System.Uri to validate a fragement, we first prepend the metadataDocumentUri // so that it becomes an absolute URI which we can validate with Uri.IsWellFormedUriString. uriStringToValidate = UriUtilsCommon.UriToString(metadataDocumentUri) + UriUtils.EnsureEscapedFragment(propertyName); } if (!Uri.IsWellFormedUriString(uriStringToValidate, UriKind.Absolute) || !ODataJsonLightUtils.IsMetadataReferenceProperty(propertyName) || propertyName[propertyName.Length - 1] == JsonLightConstants.MetadataUriFragmentIndicator) { throw new ODataException(Strings.ValidationUtils_InvalidMetadataReferenceProperty(propertyName)); } if (IsOpenMetadataReferencePropertyName(metadataDocumentUri, propertyName)) { throw new ODataException(Strings.ODataJsonLightValidationUtils_OpenMetadataReferencePropertyNotSupported(propertyName, UriUtilsCommon.UriToString(metadataDocumentUri))); } }
/// <summary> /// Converts the given <paramref name="uri"/> Uri to a string. /// If the provided baseUri is not null and is a base Uri of the <paramref name="uri"/> Uri /// the method returns the string form of the relative Uri. /// </summary> /// <param name="uri">The Uri to convert.</param> /// <param name="failOnRelativeUriWithoutBaseUri">If set to true then this method will fail if the uri specified by <paramref name="uri"/> is relative /// and no base uri is specified.</param> /// <returns>The string form of the <paramref name="uri"/> Uri. If the Uri is absolute it returns the /// string form of the <paramref name="uri"/>. If the <paramref name="uri"/> Uri is not absolute /// it returns the original string of the Uri.</returns> internal string UriToUrlAttributeValue(Uri uri, bool failOnRelativeUriWithoutBaseUri) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(uri != null, "uri != null"); if (this.UrlResolver != null) { // The resolver returns 'null' if no custom resolution is desired. Uri resultUri = this.UrlResolver.ResolveUrl(this.MessageWriterSettings.BaseUri, uri); if (resultUri != null) { return(UriUtilsCommon.UriToString(resultUri)); } } if (!uri.IsAbsoluteUri) { // NOTE: the only URIs that are allowed to be relative (e.g., failOnRelativeUriWithoutBaseUri is false) // are metadata URIs in operations; for such metadata URIs there is no base URI. if (this.MessageWriterSettings.BaseUri == null && failOnRelativeUriWithoutBaseUri) { throw new ODataException( ODataErrorStrings.ODataWriter_RelativeUriUsedWithoutBaseUriSpecified(UriUtilsCommon.UriToString(uri))); } uri = UriUtils.EnsureEscapedRelativeUri(uri); } return(UriUtilsCommon.UriToString(uri)); }
/// <summary> /// Computes and sets the field for the computed Id. /// </summary> private void ComputeAndCacheId() { if (this.computedEntityInstanceUri == null) { Uri uri = this.uriBuilder.BuildBaseUri(); uri = this.uriBuilder.BuildEntitySetUri(uri, this.entryMetadataContext.TypeContext.EntitySetName); uri = this.uriBuilder.BuildEntityInstanceUri(uri, this.entryMetadataContext.KeyProperties, this.entryMetadataContext.ActualEntityTypeName); this.computedEntityInstanceUri = uri; this.computedId = UriUtilsCommon.UriToString(uri); } }
/// <summary>Creates a URI suitable for host-agnostic comparison purposes.</summary> /// <param name="uri">URI to compare.</param> /// <returns>URI suitable for comparison.</returns> private static Uri CreateBaseComparableUri(Uri uri) { Debug.Assert(uri != null, "uri != null"); uri = new Uri(UriUtilsCommon.UriToString(uri).ToUpper(CultureInfo.InvariantCulture), UriKind.RelativeOrAbsolute); UriBuilder builder = new UriBuilder(uri); builder.Host = "h"; builder.Port = 80; builder.Scheme = "http"; return(builder.Uri); }
/// <summary> /// Determines if the specified property name is a name of an open metadata reference property. /// </summary> /// <param name="metadataDocumentUri">The metadata document uri.</param> /// <param name="propertyName">The property name in question.</param> /// <returns>true if the specified property name is a name of an open metadata reference property; false otherwise.</returns> internal static bool IsOpenMetadataReferencePropertyName(Uri metadataDocumentUri, string propertyName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(metadataDocumentUri != null, "metadataDocumentUri != null"); Debug.Assert(metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri.IsAbsoluteUri"); Debug.Assert(!String.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); // If a metadata reference property isn't based off of the known metadata document URI (for example, it points to a model on another server), // then it must be open. It is based off the known metadata document URI if it either is a fragment (i.e., starts with a hash) or starts with the known absolute URI. return(ODataJsonLightUtils.IsMetadataReferenceProperty(propertyName) && propertyName[0] != JsonLightConstants.MetadataUriFragmentIndicator && !propertyName.StartsWith(UriUtilsCommon.UriToString(metadataDocumentUri), StringComparison.OrdinalIgnoreCase)); }
/// <summary> /// Validates an operation is valid. /// </summary> /// <param name="metadataDocumentUri">The metadata document uri.</param> /// <param name="operation">The operation to validate.</param> internal static void ValidateOperation(Uri metadataDocumentUri, ODataOperation operation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(operation != null, "operation != null"); ValidationUtils.ValidateOperationMetadataNotNull(operation); string name = UriUtilsCommon.UriToString(operation.Metadata); if (metadataDocumentUri != null) { Debug.Assert(metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri.IsAbsoluteUri"); ValidateMetadataReferencePropertyName(metadataDocumentUri, name); Debug.Assert(!IsOpenMetadataReferencePropertyName(metadataDocumentUri, name), "!IsOpenMetadataReferencePropertyName(metadataDocumentUri, name)"); } }
/// <summary> /// Builds the entity instance URI with the given key property values. /// </summary> /// <param name="baseUri">The URI to append to.</param> /// <param name="keyProperties">The list of name value pair for key properties.</param> /// <param name="entityTypeName">The full name of the entity type we are building the key expression for.</param> /// <returns>The entity instance URI.</returns> internal override Uri BuildEntityInstanceUri(Uri baseUri, ICollection <KeyValuePair <string, object> > keyProperties, string entityTypeName) { DebugUtils.CheckNoExternalCallers(); ValidateBaseUri(baseUri); Debug.Assert(keyProperties != null, "keyProperties != null"); Debug.Assert(!string.IsNullOrEmpty(entityTypeName), "!string.IsNullOrEmpty(entityTypeName)"); StringBuilder builder = new StringBuilder(UriUtilsCommon.UriToString(baseUri)); // TODO: What should be done about escaping the values. // TODO: What should happen if the URL does end with a slash? this.AppendKeyExpression(builder, keyProperties, entityTypeName); return(new Uri(builder.ToString(), UriKind.Absolute)); }
private static Uri AppendSegment(Uri baseUri, string segment, bool escapeSegment) { string baseUriString = UriUtilsCommon.UriToString(baseUri); if (escapeSegment) { segment = Uri.EscapeDataString(segment); } if (baseUriString[baseUriString.Length - 1] != ODataConstants.UriSegmentSeparatorChar) { return(new Uri(baseUriString + ODataConstants.UriSegmentSeparator + segment, UriKind.Absolute)); } else { return(new Uri(baseUri, segment)); } }
/// <summary> /// Returns the string representation of the URI /// </summary> /// <param name="uri">The uri to process.</param> /// <returns>Returns the string representation of the URI.</returns> internal string UriToString(Uri uri) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(uri != null, "uri != null"); // Get the metadataDocumentUri directly from MessageWriterSettings and not using MetadataUriBuilder because in the case of getting the service document with nometadata // MetadataUriBuilder returns null, but the metadataDocumentUri is needed to calculate Absolute Uris in the service document. In any other case jsonLightOutputContext.CreateMetadataUriBuilder() should be used. ODataMetadataDocumentUri odataMetadataDocumentUri = this.jsonLightOutputContext.MessageWriterSettings.MetadataDocumentUri; Uri metadataDocumentUri = odataMetadataDocumentUri == null ? null : odataMetadataDocumentUri.BaseUri; Uri resultUri; if (this.jsonLightOutputContext.UrlResolver != null) { // The resolver returns 'null' if no custom resolution is desired. resultUri = this.jsonLightOutputContext.UrlResolver.ResolveUrl(metadataDocumentUri, uri); if (resultUri != null) { return(UriUtilsCommon.UriToString(resultUri)); } } resultUri = uri; if (!resultUri.IsAbsoluteUri) { if (!this.allowRelativeUri) { if (metadataDocumentUri == null) { throw new ODataException(Strings.ODataJsonLightSerializer_RelativeUriUsedWithoutMetadataDocumentUriOrMetadata(UriUtilsCommon.UriToString(resultUri))); } resultUri = UriUtils.UriToAbsoluteUri(metadataDocumentUri, uri); } else { resultUri = UriUtils.EnsureEscapedRelativeUri(resultUri); } } return(UriUtilsCommon.UriToString(resultUri)); }
internal string UriToUrlAttributeValue(Uri uri, bool failOnRelativeUriWithoutBaseUri) { if (base.UrlResolver != null) { Uri uri2 = base.UrlResolver.ResolveUrl(base.MessageWriterSettings.BaseUri, uri); if (uri2 != null) { return(UriUtilsCommon.UriToString(uri2)); } } if (!uri.IsAbsoluteUri) { if ((base.MessageWriterSettings.BaseUri == null) && failOnRelativeUriWithoutBaseUri) { throw new ODataException(Strings.ODataWriter_RelativeUriUsedWithoutBaseUriSpecified(UriUtilsCommon.UriToString(uri))); } uri = UriUtils.EnsureEscapedRelativeUri(uri); } return(UriUtilsCommon.UriToString(uri)); }
internal void WriteServiceDocument(ODataWorkspace defaultWorkspace) { IEnumerable <ODataResourceCollectionInfo> collections = defaultWorkspace.Collections; base.WriteTopLevelPayload(delegate { this.JsonWriter.StartObjectScope(); this.JsonWriter.WriteName("EntitySets"); this.JsonWriter.StartArrayScope(); if (collections != null) { foreach (ODataResourceCollectionInfo info in collections) { ValidationUtils.ValidateResourceCollectionInfo(info); this.JsonWriter.WriteValue(UriUtilsCommon.UriToString(info.Url)); } } this.JsonWriter.EndArrayScope(); this.JsonWriter.EndObjectScope(); }); }
/// <summary> /// Gets the metadata reference fragment from the operation metadata uri. /// i.e. if the operation metadata uri is {absolute metadata document uri}#{container-qualified-operation-name}, /// this method will return #{container-qualified-operation-name}. /// </summary> /// <param name="operation">Operation in question.</param> /// <returns>The metadata reference fragment from the operation metadata uri.</returns> private string GetOperationMetadataString(ODataOperation operation) { Debug.Assert(operation != null && operation.Metadata != null, "operation != null && operation.Metadata != null"); string operationMetadataString = UriUtilsCommon.UriToString(operation.Metadata); Debug.Assert(ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString), "ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString)"); // If we don't have a metadata document URI (which is the case with nometadata mode), just write the string form of the Uri we were given. if (this.MetadataDocumentBaseUri == null) { return(operation.Metadata.Fragment); } Debug.Assert( !ODataJsonLightValidationUtils.IsOpenMetadataReferencePropertyName(this.MetadataDocumentBaseUri, operationMetadataString), "Open metadata reference property is not supported, we should have thrown before this point."); return(JsonLightConstants.MetadataUriFragmentIndicator + ODataJsonLightUtils.GetUriFragmentFromMetadataReferencePropertyName(this.MetadataDocumentBaseUri, operationMetadataString)); }
/// <summary> /// Writes a service document in JSON format. /// </summary> /// <param name="defaultWorkspace">The default workspace to write in the service document.</param> internal void WriteServiceDocument(ODataWorkspace defaultWorkspace) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(defaultWorkspace != null, "defaultWorkspace != null"); IEnumerable <ODataResourceCollectionInfo> collections = defaultWorkspace.Collections; this.WriteTopLevelPayload( () => { // "{" this.JsonWriter.StartObjectScope(); // "EntitySets": this.JsonWriter.WriteName(JsonConstants.ODataServiceDocumentEntitySetsName); // "[" this.JsonWriter.StartArrayScope(); if (collections != null) { foreach (ODataResourceCollectionInfo collectionInfo in collections) { // validate that the collection has a non-null url. ValidationUtils.ValidateResourceCollectionInfo(collectionInfo); // Note that this is an exception case; if the Base URI is missing we will still write the relative URI. // We allow this because collections are specified to be the entity set names in JSON and // there is no base Uri in JSON. this.JsonWriter.WriteValue(UriUtilsCommon.UriToString(collectionInfo.Url)); } } // "]" this.JsonWriter.EndArrayScope(); // "}" this.JsonWriter.EndObjectScope(); }); }
/// <summary> /// Returns the string representation of the URI; Converts the URI into an absolute URI if the <paramref name="makeAbsolute"/> parameter is set to true. /// </summary> /// <param name="uri">The uri to process.</param> /// <param name="makeAbsolute">true, if the URI needs to be translated into an absolute URI; false otherwise.</param> /// <returns>If the <paramref name="makeAbsolute"/> parameter is set to true, then a string representation of an absolute URI which is either the /// specified <paramref name="uri"/> if it was absolute, or it's a combination of the BaseUri and the relative <paramref name="uri"/>; /// otherwise a string representation of the specified <paramref name="uri"/>. /// </returns> /// <remarks>This method will fail if <paramref name="makeAbsolute"/> is set to true and the specified <paramref name="uri"/> is relative and there's no base URI available.</remarks> internal string UriToUriString(Uri uri, bool makeAbsolute) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(uri != null, "uri != null"); Uri resultUri; if (this.UrlResolver != null) { // The resolver returns 'null' if no custom resolution is desired. resultUri = this.UrlResolver.ResolveUrl(this.MessageWriterSettings.BaseUri, uri); if (resultUri != null) { return(UriUtilsCommon.UriToString(resultUri)); } } resultUri = uri; if (!resultUri.IsAbsoluteUri) { if (makeAbsolute) { if (this.MessageWriterSettings.BaseUri == null) { throw new ODataException(o.Strings.ODataWriter_RelativeUriUsedWithoutBaseUriSpecified(UriUtilsCommon.UriToString(uri))); } resultUri = UriUtils.UriToAbsoluteUri(this.MessageWriterSettings.BaseUri, uri); } else { // NOTE: the only URIs that are allowed to be relative are metadata URIs // in operations; for such metadata URIs there is no base URI. resultUri = UriUtils.EnsureEscapedRelativeUri(resultUri); } } return(UriUtilsCommon.UriToString(resultUri)); }
/// <summary> /// Returns a hash set of function imports (actions and functions) in the given entry. /// </summary> /// <param name="entry">The entry in question.</param> /// <param name="model">The edm model to resolve function imports.</param> /// <param name="metadataDocumentUri">The metadata document uri.</param> /// <returns>The hash set of function imports (actions and functions) in the given entry.</returns> private static HashSet <IEdmFunctionImport> GetFunctionImportsInEntry(ODataEntry entry, IEdmModel model, Uri metadataDocumentUri) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(model != null, "model != null"); Debug.Assert(metadataDocumentUri != null && metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri != null && metadataDocumentUri.IsAbsoluteUri"); HashSet <IEdmFunctionImport> functionImportsInEntry = new HashSet <IEdmFunctionImport>(EqualityComparer <IEdmFunctionImport> .Default); IEnumerable <ODataOperation> operations = ODataUtilsInternal.ConcatEnumerables((IEnumerable <ODataOperation>)entry.NonComputedActions, (IEnumerable <ODataOperation>)entry.NonComputedFunctions); if (operations != null) { foreach (ODataOperation operation in operations) { Debug.Assert(operation.Metadata != null, "operation.Metadata != null"); string operationMetadataString = UriUtilsCommon.UriToString(operation.Metadata); Debug.Assert( ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString), "ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString)"); Debug.Assert( operationMetadataString[0] == JsonLightConstants.MetadataUriFragmentIndicator || metadataDocumentUri.IsBaseOf(operation.Metadata), "operationMetadataString[0] == JsonLightConstants.MetadataUriFragmentIndicator || metadataDocumentUri.IsBaseOf(operation.Metadata)"); string fullyQualifiedOperationName = ODataJsonLightUtils.GetUriFragmentFromMetadataReferencePropertyName(metadataDocumentUri, operationMetadataString); IEnumerable <IEdmFunctionImport> functionImports = model.ResolveFunctionImports(fullyQualifiedOperationName); if (functionImports != null) { foreach (IEdmFunctionImport functionImport in functionImports) { functionImportsInEntry.Add(functionImport); } } } } return(functionImportsInEntry); }
internal override string GetId() { DebugUtils.CheckNoExternalCallers(); // If the Id, ReadLink, or EditLink were on the wire (in that order), use that wire value for the Id. // Otherwise compute it based on the key values. We specifically do not want to use the ReadLink/EditLink // values if they were already previously computed instead of just being directly set on the entry. if (this.entryMetadataContext.Entry.HasNonComputedId) { return(this.entryMetadataContext.Entry.NonComputedId); } if (this.entryMetadataContext.Entry.HasNonComputedReadLink) { return(UriUtilsCommon.UriToString(this.entryMetadataContext.Entry.NonComputedReadLink)); } if (this.entryMetadataContext.Entry.NonComputedEditLink != null) { return(UriUtilsCommon.UriToString(this.entryMetadataContext.Entry.NonComputedEditLink)); } return(this.ComputedId); }
/// <summary> /// Resolves a navigation property name to an IEdmNavigationProperty. /// </summary> /// <param name="entityType">Entity Type to look for the navigation property on.</param> /// <param name="navigationPropertyName">Navigation property name to find.</param> /// <returns>Returns the navigation property of throws an exception if it cannot be found.</returns> private IEdmNavigationProperty ResolveNavigationProperty(IEdmEntityType entityType, string navigationPropertyName) { IEdmNavigationProperty navigationProperty = null; IEdmProperty property = entityType.FindProperty(navigationPropertyName); navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidPropertyForEntityReferenceLinkUri(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), navigationPropertyName)); } return(navigationProperty); }
/// <summary> /// Applies the model and validates the metadata URI against it. /// </summary> /// <param name="expectedPayloadKind">The payload kind we expect the metadata URI to conform to.</param> /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param> /// <param name="version">The version of the payload being read.</param> private void ParseMetadataUri(ODataPayloadKind expectedPayloadKind, ODataReaderBehavior readerBehavior, ODataVersion version) { ODataPayloadKind detectedPayloadKind = this.ParseMetadataUriFragment(this.parseResult.Fragment, readerBehavior, version); // unsupported payload kind indicates that this is during payload kind detection, so we should not fail. bool detectedPayloadKindMatchesExpectation = detectedPayloadKind == expectedPayloadKind || expectedPayloadKind == ODataPayloadKind.Unsupported; if (detectedPayloadKind == ODataPayloadKind.Collection) { // If the detected payload kind is 'collection' it can always also be treated as a property. this.parseResult.DetectedPayloadKinds = new[] { ODataPayloadKind.Collection, ODataPayloadKind.Property }; if (expectedPayloadKind == ODataPayloadKind.Property) { detectedPayloadKindMatchesExpectation = true; } } else { this.parseResult.DetectedPayloadKinds = new[] { detectedPayloadKind }; } // If the expected and detected payload kinds don't match and we are not running payload kind detection // right now (payloadKind == ODataPayloadKind.Unsupported) and we did not detect a collection kind for // an expected property kind (which is allowed), fail. if (!detectedPayloadKindMatchesExpectation) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_MetadataUriDoesNotMatchExpectedPayloadKind(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), expectedPayloadKind.ToString())); } // NOTE: we interpret an empty select query option to mean that nothing should be projected // (whereas a missing select query option means everything should be projected). string selectQueryOption = this.parseResult.SelectQueryOption; if (selectQueryOption != null) { if (detectedPayloadKind != ODataPayloadKind.Feed && detectedPayloadKind != ODataPayloadKind.Entry) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidPayloadKindWithSelectQueryOption(expectedPayloadKind.ToString())); } } }
private ODataPayloadKind ParseMetadataUriFragment(string fragment, ODataReaderBehavior readerBehavior, ODataVersion version) { // remove any query options like $select that may have been embedded in the fragment. int indexOfQueryOptionSeparator = fragment.IndexOf(JsonLightConstants.MetadataUriQueryOptionSeparator); if (indexOfQueryOptionSeparator > 0) { // Extract the $select query option value from the fragment if it exists string fragmentQueryOptions = fragment.Substring(indexOfQueryOptionSeparator); this.parseResult.SelectQueryOption = ExtractSelectQueryOption(fragmentQueryOptions); fragment = fragment.Substring(0, indexOfQueryOptionSeparator); } string[] parts = fragment.Split(JsonLightConstants.MetadataUriFragmentPartSeparator); int partCount = parts.Length; ODataPayloadKind detectedPayloadKind = ODataPayloadKind.Unsupported; EdmTypeResolver edmTypeResolver = new EdmTypeReaderResolver(this.model, readerBehavior, version); var foundAssociationLinksSegment = fragment.IndexOf(ODataConstants.AssociationLinkSegmentName, StringComparison.Ordinal); if (foundAssociationLinksSegment > -1) { detectedPayloadKind = this.ParseAssociationLinks(edmTypeResolver, partCount, parts, readerBehavior, version); } else { switch (partCount) { case 1: // Service document: no fragment if (fragment.Length == 0) { detectedPayloadKind = ODataPayloadKind.ServiceDocument; break; } if (parts[0].Equals(JsonLightConstants.MetadataUriFragmentNull, StringComparison.OrdinalIgnoreCase)) { detectedPayloadKind = ODataPayloadKind.Property; this.parseResult.IsNullProperty = true; break; } IEdmEntitySet entitySet = this.model.ResolveEntitySet(parts[0]); if (entitySet != null) { // Feed: {schema.entity-container.entity-set} this.parseResult.EntitySet = entitySet; this.parseResult.EdmType = edmTypeResolver.GetElementType(entitySet); detectedPayloadKind = ODataPayloadKind.Feed; break; } // Property: {schema.type} or Collection({schema.type}) where schema.type is primitive or complex. this.parseResult.EdmType = this.ResolveType(parts[0], readerBehavior, version); Debug.Assert( this.parseResult.EdmType.TypeKind == EdmTypeKind.Primitive || this.parseResult.EdmType.TypeKind == EdmTypeKind.Complex || this.parseResult.EdmType.IsNonEntityCollectionType(), "The first metadata URI segment must be a set or a non-entity type."); detectedPayloadKind = this.parseResult.EdmType is IEdmCollectionType ? ODataPayloadKind.Collection : ODataPayloadKind.Property; break; case 2: // Entry: {schema.entity-container.entity-set}/@Element // Feed with type cast: {schema.entity-container.entity-set}/{type-cast} detectedPayloadKind = this.ResolveEntitySet( parts[0], (IEdmEntitySet resolvedEntitySet) => { IEdmEntityType entitySetElementType = edmTypeResolver.GetElementType(resolvedEntitySet); if (string.CompareOrdinal(JsonLightConstants.MetadataUriFragmentItemSelector, parts[1]) == 0) { this.parseResult.EdmType = entitySetElementType; return(ODataPayloadKind.Entry); } else { this.parseResult.EdmType = this.ResolveTypeCast(resolvedEntitySet, parts[1], readerBehavior, version, entitySetElementType); return(ODataPayloadKind.Feed); } }); break; case 3: detectedPayloadKind = this.ResolveEntitySet( parts[0], (IEdmEntitySet resolvedEntitySet) => { IEdmEntityType entitySetElementType = edmTypeResolver.GetElementType(resolvedEntitySet); // Entry with type cast: {schema.entity-container.entity-set}/{type-cast}/@Element this.parseResult.EdmType = this.ResolveTypeCast(resolvedEntitySet, parts[1], readerBehavior, version, entitySetElementType); this.ValidateMetadataUriFragmentItemSelector(parts[2]); return(ODataPayloadKind.Entry); }); break; default: throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_FragmentWithInvalidNumberOfParts(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), partCount, 3)); } } return(detectedPayloadKind); }
/// <summary> /// Returns the parse results of the metadata uri if it has a AssociationLink in the uri /// </summary> /// <param name="edmTypeResolver">Edm Type Resolver to determine entityset type element.</param> /// <param name="partCount">Number of split parts the metadata fragment is split into.</param> /// <param name="parts">The actual metadata fragment parts.</param> /// <param name="readerBehavior">The reader behavior.</param> /// <param name="version">The odata version.</param> /// <returns>Returns with an EntityReferenceLink or Links depending on the Uri, sets the parse results with the navigation, and set</returns> private ODataPayloadKind ParseAssociationLinks(EdmTypeResolver edmTypeResolver, int partCount, string[] parts, ODataReaderBehavior readerBehavior, ODataVersion version) { return(this.ResolveEntitySet( parts[0], (IEdmEntitySet resolvedEntitySet) => { ODataPayloadKind detectedPayloadKind = ODataPayloadKind.Unsupported; IEdmNavigationProperty navigationProperty; switch (partCount) { case 3: if (string.CompareOrdinal(ODataConstants.AssociationLinkSegmentName, parts[1]) == 0) { // Entity reference links: {schema.entity-container.entity-set}/$links/{nav-property} navigationProperty = this.ResolveEntityReferenceLinkMetadataFragment(edmTypeResolver, resolvedEntitySet, (string)null, parts[2], readerBehavior, version); detectedPayloadKind = this.SetEntityLinkParseResults(navigationProperty, null); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidAssociationLink(UriUtilsCommon.UriToString(this.parseResult.MetadataUri))); } break; case 4: if (string.CompareOrdinal(ODataConstants.AssociationLinkSegmentName, parts[1]) == 0) { // Entry with property: {schema.entity-container.entity-set}/$links/{col-nav-property}/@Element // Entry with property: {schema.entity-container.entity-set}/$links/{ref-nav-property}/@Element (invalid, will throw) navigationProperty = this.ResolveEntityReferenceLinkMetadataFragment(edmTypeResolver, resolvedEntitySet, null, parts[2], readerBehavior, version); this.ValidateLinkMetadataUriFragmentItemSelector(parts[3]); detectedPayloadKind = this.SetEntityLinkParseResults(navigationProperty, parts[3]); } else if (string.CompareOrdinal(ODataConstants.AssociationLinkSegmentName, parts[2]) == 0) { // Entry with property: {schema.entity-container.entity-set}/type/$links/{colproperty} navigationProperty = this.ResolveEntityReferenceLinkMetadataFragment(edmTypeResolver, resolvedEntitySet, parts[1], parts[3], readerBehavior, version); detectedPayloadKind = this.SetEntityLinkParseResults(navigationProperty, null); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidAssociationLink(UriUtilsCommon.UriToString(this.parseResult.MetadataUri))); } break; case 5: if (string.CompareOrdinal(ODataConstants.AssociationLinkSegmentName, parts[2]) == 0) { // Entry with property: {schema.entity-container.entity-set}/type/$links/{navproperty}/@Element navigationProperty = this.ResolveEntityReferenceLinkMetadataFragment(edmTypeResolver, resolvedEntitySet, parts[1], parts[3], readerBehavior, version); this.ValidateLinkMetadataUriFragmentItemSelector(parts[2]); detectedPayloadKind = this.SetEntityLinkParseResults(navigationProperty, parts[4]); } else { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidAssociationLink(UriUtilsCommon.UriToString(this.parseResult.MetadataUri))); } break; default: throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidAssociationLink(UriUtilsCommon.UriToString(this.parseResult.MetadataUri))); } return detectedPayloadKind; })); }
/// <summary> /// Resolves a type. /// </summary> /// <param name="typeName">The type name.</param> /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param> /// <param name="version">The version of the payload being read.</param> /// <returns>The resolved Edm type.</returns> private IEdmType ResolveType(string typeName, ODataReaderBehavior readerBehavior, ODataVersion version) { string typeNameToResolve = EdmLibraryExtensions.GetCollectionItemTypeName(typeName) ?? typeName; EdmTypeKind typeKind; IEdmType resolvedType = MetadataUtils.ResolveTypeNameForRead(this.model, /*expectedType*/ null, typeNameToResolve, readerBehavior, version, out typeKind); if (resolvedType == null || resolvedType.TypeKind != EdmTypeKind.Primitive && resolvedType.TypeKind != EdmTypeKind.Complex) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntitySetNameOrTypeName(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), typeName)); } resolvedType = typeNameToResolve == typeName ? resolvedType : EdmLibraryExtensions.GetCollectionType(resolvedType.ToTypeReference(true /*nullable*/)); return(resolvedType); }
/// <summary> /// Resolves an entity set with an optional type cast and updates the parse result. /// </summary> /// <param name="entitySet">The entity set to resolve the type cast against.</param> /// <param name="typeCast">The optional type cast.</param> /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param> /// <param name="version">The version of the payload being read.</param> /// <param name="entitySetElementType">The type of the given entity set.</param> /// <returns>The resolved entity type.</returns> private IEdmEntityType ResolveTypeCast(IEdmEntitySet entitySet, string typeCast, ODataReaderBehavior readerBehavior, ODataVersion version, IEdmEntityType entitySetElementType) { Debug.Assert(entitySet != null, "entitySet != null"); IEdmEntityType entityType = entitySetElementType; // Parse the type cast if it exists if (!string.IsNullOrEmpty(typeCast)) { EdmTypeKind typeKind; entityType = MetadataUtils.ResolveTypeNameForRead(this.model, /*expectedType*/ null, typeCast, readerBehavior, version, out typeKind) as IEdmEntityType; if (entityType == null) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntityTypeInTypeCast(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), typeCast)); } // Validate that the entity type is assignable to the base type of the set if (!entitySetElementType.IsAssignableFrom(entityType)) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_IncompatibleEntityTypeInTypeCast(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), typeCast, entitySetElementType.FullName(), entitySet.FullName())); } } return(entityType); }
/// <summary> /// Resolves the entity set. /// </summary> /// <param name="entitySetPart">The entity set part.</param> /// <param name="resolvedEntitySet">The resolved entity set.</param> /// <returns>Returns the OData Payload Kind</returns> private ODataPayloadKind ResolveEntitySet(string entitySetPart, Func <IEdmEntitySet, ODataPayloadKind> resolvedEntitySet) { IEdmEntitySet entitySet = this.model.ResolveEntitySet(entitySetPart); if (entitySet != null) { this.parseResult.EntitySet = entitySet; return(resolvedEntitySet(entitySet)); } throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntitySetName(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), entitySetPart)); }
/// <summary> /// Set the EntityLinks Parse results. /// </summary> /// <param name="navigationProperty">Navigation property to add to the results.</param> /// <param name="singleElement">Single element string, used to confirm if this is an error case or not.</param> /// <returns>Returns ReferenceLink or Collection Link based on the navigation and at element</returns> private ODataPayloadKind SetEntityLinkParseResults(IEdmNavigationProperty navigationProperty, string singleElement) { ODataPayloadKind detectedPayloadKind = ODataPayloadKind.Unsupported; this.parseResult.NavigationProperty = navigationProperty; detectedPayloadKind = navigationProperty.Type.IsCollection() ? ODataPayloadKind.EntityReferenceLinks : ODataPayloadKind.EntityReferenceLink; if (singleElement != null && string.CompareOrdinal(JsonLightConstants.MetadataUriFragmentItemSelector, singleElement) == 0) { if (navigationProperty.Type.IsCollection()) { detectedPayloadKind = ODataPayloadKind.EntityReferenceLink; } else { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidSingletonNavPropertyForEntityReferenceLinkUri(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), navigationProperty.Name, singleElement)); } } return(detectedPayloadKind); }
/// <summary> /// Validate the Metadata Uri Fragment is @Element for a non $links metadata uri, throws if its not correct /// </summary> /// <param name="elementSelector">Element selector.</param> private void ValidateMetadataUriFragmentItemSelector(string elementSelector) { if (string.CompareOrdinal(JsonLightConstants.MetadataUriFragmentItemSelector, elementSelector) != 0) { throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntityWithTypeCastUriSuffix(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), elementSelector, JsonLightConstants.MetadataUriFragmentItemSelector)); } }