/// <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;
        }
示例#2
0
        /// <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;
            }
示例#5
0
 /// <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));
        }
示例#7
0
 /// <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);
 }
示例#8
0
        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
            });
        }
示例#10
0
        /// <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;
 }
示例#12
0
        /// <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);
        }