/// <summary> /// Constructs an instance of <see cref="ODataResourceMetadataContext"/>. /// </summary> /// <param name="resource">The resource instance.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource.</param> protected ODataResourceMetadataContext(ODataResource resource, IODataResourceTypeContext typeContext) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(typeContext != null, "typeContext != null"); this.resource = resource; this.typeContext = typeContext; }
/// <summary> /// Gets canonical url of current resource. /// </summary> /// <returns>The canonical url of current resource.</returns> public virtual Uri GetCanonicalUrl() { if (this.canonicalUrl != null) { return(this.canonicalUrl); } // canonicalUrl = HasNonComputedId if (this.resource.HasNonComputedId) { return(this.canonicalUrl = this.resource.NonComputedId); } // Compute canonicalUrl from parent canonicalUrl var parent = this.ParentMetadataBuilder as ODataConventionalResourceMetadataBuilder; if (this.NameAsProperty != null && parent != null && parent.GetCanonicalUrl() != null) { // If parent is collection of complex, the canonical url for this resource should be null. if (parent.IsFromCollection && !(parent is ODataConventionalEntityMetadataBuilder)) { return(this.canonicalUrl = null); } // canonicalUrl = parentCanonicalUrl[/typeCast]/propertyName // Different from edit url and read url, canonical url only needs type cast when the property is defined on derived type. this.canonicalUrl = parent.GetCanonicalUrl(); IODataResourceTypeContext typeContext = parent.ResourceMetadataContext.TypeContext; if (parent.ResourceMetadataContext.ActualResourceTypeName != typeContext.ExpectedResourceTypeName) { // Do not append type cast if we know that the navigation property is in base type, not in derived type. ODataResourceTypeContext.ODataResourceTypeContextWithModel typeContextWithModel = typeContext as ODataResourceTypeContext.ODataResourceTypeContextWithModel; if (typeContextWithModel == null || typeContextWithModel.ExpectedResourceType.FindProperty( this.NameAsProperty) == null) { this.canonicalUrl = this.UriBuilder.AppendTypeSegment(canonicalUrl, parent.ResourceMetadataContext.ActualResourceTypeName); } } this.canonicalUrl = new Uri(string.Concat(this.canonicalUrl, "/", this.NameAsProperty), UriKind.RelativeOrAbsolute); } else { if (this.ODataUri != null && this.ODataUri.Path.Count != 0) { this.canonicalUrl = this.ODataUri.BuildUri(ODataUrlKeyDelimiter.Parentheses); } } return(this.canonicalUrl); }
/// <summary> /// Creates the metadata builder for the given resource. If such a builder is set, asking for payload /// metadata properties (like EditLink) of the resource may return a value computed by convention, /// depending on the metadata level and whether the user manually set an edit link or not. /// </summary> /// <param name="resource">The resource to create the metadata builder for.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource or resource set.</param> /// <param name="serializationInfo">The serialization info for the resource.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="isResponse">true if the resource metadata builder to create should be for a response payload; false for a request.</param> /// <param name="keyAsSegment">true if keys should go in separate segments in auto-generated URIs, false if they should go in parentheses. /// A null value means the user hasn't specified a preference and we should look for an annotation in the entity container, if available.</param> /// <param name="odataUri">The OData Uri.</param> /// <returns>The created metadata builder.</returns> internal abstract ODataResourceMetadataBuilder CreateResourceMetadataBuilder( ODataResourceBase resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, SelectedPropertiesNode selectedProperties, bool isResponse, bool keyAsSegment, ODataUri odataUri);
/// <summary> /// Constructs an instance of <see cref="ODataResourceMetadataContextWithModel"/>. /// </summary> /// <param name="resource">The resource instance.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="metadataContext">The metadata context to use.</param> /// <param name="selectedProperties">The selected properties.</param> internal ODataResourceMetadataContextWithModel(ODataResource resource, IODataResourceTypeContext typeContext, IEdmStructuredType actualResourceType, IODataMetadataContext metadataContext, SelectedPropertiesNode selectedProperties) : base(resource, typeContext) { Debug.Assert(actualResourceType != null, "actualResourceType != null"); Debug.Assert(metadataContext != null, "metadataContext != null"); Debug.Assert(selectedProperties != null, "selectedProperties != null"); this.actualResourceType = actualResourceType; this.metadataContext = metadataContext; this.selectedProperties = selectedProperties; }
/// <summary> /// Creates the metadata builder for the given resource. If such a builder is set, asking for payload /// metadata properties (like EditLink) of the resource may return a value computed by convention, /// depending on the metadata level and whether the user manually set an edit link or not. /// </summary> /// <param name="resource">The resource to create the metadata builder for.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource or resource set.</param> /// <param name="serializationInfo">The serialization info for the resource.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="isResponse">true if the resource metadata builder to create should be for a response payload; false for a request.</param> /// <param name="keyAsSegment">true if keys should go in separate segments in auto-generated URIs, false if they should go in parentheses.</param> /// <param name="odataUri">The OData Uri.</param> /// <param name="settings">The settings to use when creating the resource builder.</param> /// <returns>The created metadata builder.</returns> internal override ODataResourceMetadataBuilder CreateResourceMetadataBuilder( ODataResourceBase resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, SelectedPropertiesNode selectedProperties, bool isResponse, bool keyAsSegment, ODataUri odataUri, ODataMessageWriterSettings settings) { return(ODataResourceMetadataBuilder.Null); }
/// <summary> /// Creates an instance of <see cref="ODataResourceMetadataContext"/>. /// </summary> /// <param name="resource">The resource instance.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource.</param> /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="metadataContext">The metadata context to use.</param> /// <param name="selectedProperties">The selected properties.</param> /// <returns>A new instance of <see cref="ODataResourceMetadataContext"/>.</returns> internal static ODataResourceMetadataContext Create( ODataResource resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, IODataMetadataContext metadataContext, SelectedPropertiesNode selectedProperties) { if (serializationInfo != null) { return(new ODataResourceMetadataContextWithoutModel(resource, typeContext, serializationInfo)); } return(new ODataResourceMetadataContextWithModel(resource, typeContext, actualResourceType, metadataContext, selectedProperties)); }
/// <summary> /// Creates the metadata builder for the given resource. If such a builder is set, asking for payload /// metadata properties (like EditLink) of the resource may return a value computed by convention, /// depending on the metadata level and whether the user manually set an edit link or not. /// </summary> /// <param name="resource">The resource to create the metadata builder for.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource or resource set.</param> /// <param name="serializationInfo">The serialization info for the resource.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="isResponse">true if the resource metadata builder to create should be for a response payload; false for a request.</param> /// <param name="keyAsSegment">true if keys should go in separate segments in auto-generated URIs, false if they should go in parentheses.</param> /// <param name="odataUri">The OData Uri.</param> /// <returns>The created metadata builder.</returns> internal override ODataResourceMetadataBuilder CreateResourceMetadataBuilder( ODataResourceBase resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, SelectedPropertiesNode selectedProperties, bool isResponse, bool keyAsSegment, ODataUri odataUri) { // For minimal metadata we don't want to change the metadata builder that's currently on the resource because the resource might come from a JSON light // reader and it would contain the metadata builder from the reader. Until we give the user the ability to choose whether to write what was reported // by the reader versus what was on the wire, we no-op here so the writer will just write what's on the OM for now. return(null); }
private bool TryComputeIdFromParent(out Uri uri) { try { ODataConventionalResourceMetadataBuilder parent = this.ParentMetadataBuilder as ODataConventionalResourceMetadataBuilder; if (parent != null && parent != this) { // Get the parent canonical url uri = parent.GetCanonicalUrl(); if (uri != null) { // And append cast (if needed). // A cast segment if the navigation property is defined on a type derived from the type expected. IODataResourceTypeContext typeContext = parent.ResourceMetadataContext.TypeContext; if (parent.ResourceMetadataContext.ActualResourceTypeName != typeContext.ExpectedResourceTypeName) { // Do not append type cast if we know that the navigation property is in base type, not in derived type. ODataResourceTypeContext.ODataResourceTypeContextWithModel typeContextWithModel = typeContext as ODataResourceTypeContext.ODataResourceTypeContextWithModel; if (typeContextWithModel == null || typeContextWithModel.ExpectedResourceType.FindProperty( this.ResourceMetadataContext.TypeContext.NavigationSourceName) == null) { uri = new Uri(UriUtils.EnsureTaillingSlash(uri), parent.ResourceMetadataContext.ActualResourceTypeName); } } return(true); } } } catch (ODataException) { } uri = null; return(false); }
/// <summary> /// Creates an instance of <see cref="ODataResourceMetadataContext"/>. /// </summary> /// <param name="resource">The resource instance.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource.</param> /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="metadataContext">The metadata context to use.</param> /// <param name="selectedProperties">The selected properties.</param> /// <param name="metadataSelector">Informs the metadata builder which properties, functions, actions, links to omit.</param> /// <param name="requiresId">True if the resource requires an id, false if it is a non-deleted resource in a delta request payload.</param> /// <returns>A new instance of <see cref="ODataResourceMetadataContext"/>.</returns> internal static ODataResourceMetadataContext Create( ODataResourceBase resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, IODataMetadataContext metadataContext, SelectedPropertiesNode selectedProperties, ODataMetadataSelector metadataSelector, bool requiresId = true) { if (serializationInfo != null) { return(new ODataResourceMetadataContextWithoutModel(resource, typeContext, serializationInfo, requiresId) { ActualResourceType = actualResourceType }); } return(new ODataResourceMetadataContextWithModel(resource, typeContext, actualResourceType, metadataContext, selectedProperties, metadataSelector, requiresId) { ActualResourceType = actualResourceType }); }
/// <summary> /// Creates the metadata builder for the given resource. If such a builder is set, asking for payload /// metadata properties (like EditLink) of the resource may return a value computed by convention, /// depending on the metadata level and whether the user manually set an edit link or not. /// </summary> /// <param name="resource">The resource to create the metadata builder for.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource or resource set.</param> /// <param name="serializationInfo">The serialization info for the resource.</param> /// <param name="actualResourceType">The structured type of the resource.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="isResponse">true if the resource metadata builder to create should be for a response payload; false for a request.</param> /// <param name="keyAsSegment">true if keys should go in separate segments in auto-generated URIs, false if they should go in parentheses.</param> /// <param name="odataUri">The OData Uri.</param> /// <param name="settings">OData message writer settings.</param> /// <returns>The created metadata builder.</returns> internal override ODataResourceMetadataBuilder CreateResourceMetadataBuilder( ODataResourceBase resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo, IEdmStructuredType actualResourceType, SelectedPropertiesNode selectedProperties, bool isResponse, bool keyAsSegment, ODataUri odataUri, ODataMessageWriterSettings settings) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(typeContext != null, "typeContext != null"); Debug.Assert(selectedProperties != null, "selectedProperties != null"); IODataMetadataContext metadataContext = new ODataMetadataContext( isResponse, this.model, this.NonNullMetadataDocumentUri, odataUri); ODataConventionalUriBuilder uriBuilder = new ODataConventionalUriBuilder(metadataContext.ServiceBaseUri, keyAsSegment ? ODataUrlKeyDelimiter.Slash : ODataUrlKeyDelimiter.Parentheses); IODataResourceMetadataContext resourceMetadataContext = ODataResourceMetadataContext.Create(resource, typeContext, serializationInfo, actualResourceType, metadataContext, selectedProperties, settings != null ? settings.MetadataSelector : null); // Create ODataConventionalEntityMetadataBuilder if actualResourceType is entity type or typeContext.NavigationSourceKind is not none (complex type would be none) for no model scenario. if (actualResourceType != null && actualResourceType.TypeKind == EdmTypeKind.Entity || actualResourceType == null && typeContext.NavigationSourceKind != EdmNavigationSourceKind.None) { return(new ODataConventionalEntityMetadataBuilder(resourceMetadataContext, metadataContext, uriBuilder)); } else { return(new ODataConventionalResourceMetadataBuilder(resourceMetadataContext, metadataContext, uriBuilder)); } }
/// <summary> /// Constructs an instance of <see cref="ODataResourceMetadataContextWithoutModel"/>. /// </summary> /// <param name="resource">The resource instance.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the resource.</param> /// <param name="serializationInfo">The serialization info of the resource for writing without model.</param> internal ODataResourceMetadataContextWithoutModel(ODataResource resource, IODataResourceTypeContext typeContext, ODataResourceSerializationInfo serializationInfo) : base(resource, typeContext) { Debug.Assert(serializationInfo != null, "serializationInfo != null"); this.serializationInfo = serializationInfo; }
/// <summary> /// Gets a resource metadata builder for the given resource. /// </summary> /// <param name="resourceState">Resource state to use as reference for information needed by the builder.</param> /// <param name="useKeyAsSegment">true if keys should go in separate segments in auto-generated URIs, false if they should go in parentheses.</param> /// <param name="isDelta">true if the payload being read is a delta payload</param> /// <returns>A resource metadata builder.</returns> public ODataResourceMetadataBuilder GetResourceMetadataBuilderForReader(IODataJsonLightReaderResourceState resourceState, bool useKeyAsSegment, bool isDelta = false) { Debug.Assert(resourceState != null, "resource != null"); // Only apply the conventional template builder on response. On a request we would only report what's on the wire. if (resourceState.MetadataBuilder == null) { ODataResourceBase resource = resourceState.Resource; if (this.isResponse && !isDelta) { ODataTypeAnnotation typeAnnotation = resource.TypeAnnotation; IEdmStructuredType structuredType = null; if (typeAnnotation != null) { if (typeAnnotation.Type != null) { // First try ODataTypeAnnotation.Type (for perf improvement) structuredType = typeAnnotation.Type as IEdmStructuredType; } else if (typeAnnotation.TypeName != null) { // Then try ODataTypeAnnotation.TypeName structuredType = this.model.FindType(typeAnnotation.TypeName) as IEdmStructuredType; } } if (structuredType == null) { // No type name read from the payload. Use resource type from model. structuredType = resourceState.ResourceType; } IEdmNavigationSource navigationSource = resourceState.NavigationSource; IEdmEntityType navigationSourceElementType = this.edmTypeResolver.GetElementType(navigationSource); IODataResourceTypeContext typeContext = ODataResourceTypeContext.Create( /*serializationInfo*/ null, navigationSource, navigationSourceElementType, resourceState.ResourceTypeFromMetadata ?? resourceState.ResourceType, /*throwIfMissingTypeInfo*/ true); IODataResourceMetadataContext resourceMetadataContext = ODataResourceMetadataContext.Create(resource, typeContext, /*serializationInfo*/ null, structuredType, this, resourceState.SelectedProperties); ODataConventionalUriBuilder uriBuilder = new ODataConventionalUriBuilder(this.ServiceBaseUri, useKeyAsSegment ? ODataUrlKeyDelimiter.Slash : ODataUrlKeyDelimiter.Parentheses); if (structuredType.IsODataEntityTypeKind()) { resourceState.MetadataBuilder = new ODataConventionalEntityMetadataBuilder(resourceMetadataContext, this, uriBuilder); } else { resourceState.MetadataBuilder = new ODataConventionalResourceMetadataBuilder(resourceMetadataContext, this, uriBuilder); } } else { resourceState.MetadataBuilder = new NoOpResourceMetadataBuilder(resource); } } return(resourceState.MetadataBuilder); }