Пример #1
0
        /// <summary>
        /// Get the ODataStreamReferenceValue instance containing the metadata for named stream property.
        /// </summary>
        /// <param name="entityToSerialize">Entity that is currently being serialized.</param>
        /// <param name="namedStreamProperty">Named stream property for which the link element needs to be written.</param>
        /// <returns>
        /// An instance of ODataStreamReferenceValue containing all the metadata about the named stream property.
        /// </returns>
        private ODataStreamReferenceValue GetNamedStreamPropertyValue(EntityToSerialize entityToSerialize, ResourceProperty namedStreamProperty)
        {
            Debug.Assert(entityToSerialize != null, "entityToSerialize != null");
            Debug.Assert(namedStreamProperty != null, "namedStreamProperty != null");
            Debug.Assert(namedStreamProperty.IsOfKind(ResourcePropertyKind.Stream), "namedStreamProperty.IsOfKind(ResourcePropertyKind.Stream)");

            string mediaETag;
            Uri    readStreamUri;
            string mediaContentType;

            this.Service.StreamProvider.GetStreamDescription(entityToSerialize.Entity, namedStreamProperty, this.Service.OperationContext, out mediaETag, out readStreamUri, out mediaContentType);
            Debug.Assert(WebUtil.IsETagValueValid(mediaETag, true), "WebUtil.IsETagValueValid(mediaETag, true)");

            ODataStreamReferenceValue streamReferenceValue = new ODataStreamReferenceValue();

            this.PayloadMetadataPropertyManager.SetContentType(streamReferenceValue, mediaContentType);

            this.PayloadMetadataPropertyManager.SetEditLink(
                streamReferenceValue,
                () =>
            {
                Uri relativeUri = entityToSerialize.SerializedKey.RelativeEditLink;
                return(RequestUriProcessor.AppendUnescapedSegment(relativeUri, namedStreamProperty.Name));
            });

            if (!string.IsNullOrEmpty(mediaETag))
            {
                this.PayloadMetadataPropertyManager.SetETag(streamReferenceValue, mediaETag);
            }

            // Note if readStreamUri is null, the self link for the named stream will be omitted.
            this.PayloadMetadataPropertyManager.SetReadLink(streamReferenceValue, () => readStreamUri);
            return(streamReferenceValue);
        }
Пример #2
0
        private static ODataAssociationLink GetAssociationLink(Uri relativeUri, ResourceProperty navigationProperty)
        {
            Uri uri = RequestUriProcessor.AppendUnescapedSegment(RequestUriProcessor.AppendEscapedSegment(relativeUri, "$links"), navigationProperty.Name);

            return(new ODataAssociationLink {
                Name = navigationProperty.Name, Url = uri
            });
        }
Пример #3
0
        internal static Uri GetIdAndEditLink(object resource, ResourceType resourceType, DataServiceProviderWrapper provider, ResourceSetWrapper container, Uri absoluteServiceUri, out Uri id)
        {
            string segmentIdentifier = GetObjectKey(resource, resourceType, provider, container.Name);
            Uri    uri = RequestUriProcessor.AppendEscapedSegment(absoluteServiceUri, segmentIdentifier);

            id = uri;
            if (container.HasNavigationPropertyOrNamedStreamsOnDerivedTypes(provider))
            {
                uri = RequestUriProcessor.AppendUnescapedSegment(uri, resourceType.FullName);
            }
            return(uri);
        }
Пример #4
0
        /// <summary>
        /// Gets the target link value for an <see cref="ODataOperation"/>
        /// </summary>
        /// <param name="entityToSerialize">The current entity being serialized.</param>
        /// <param name="operation">The operation to generate the link for.</param>
        /// <param name="entityHasMultipleActionsWithSameName">Whether or not there are multiple operations in the current scope with the same name as the current operation.</param>
        /// <returns>Uri representing link to use for invoking this operation.</returns>
        internal Uri BuildTargetLink(EntityToSerialize entityToSerialize, OperationWrapper operation, bool entityHasMultipleActionsWithSameName)
        {
            Debug.Assert(entityToSerialize != null, "entityToSerialize != null");
            Debug.Assert(operation != null, "operation != null");
            Debug.Assert(operation.BindingParameter != null, "operation.BindingParameter != null");
            Debug.Assert(operation.BindingParameter.ParameterType != null, "operation.BindingParameter.ParameterType != null");

            string targetSegment = operation.GetActionTargetSegmentByResourceType(entityToSerialize.ResourceType, this.namespaceName);

            // If there are multiple operations with the same name, then using the edit link of the entry would cause the target to potentially resolve to the wrong
            // operation. Instead, use the actual binding type of the specific operation.
            if (entityHasMultipleActionsWithSameName)
            {
                Uri editLinkWithBindingType = RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.AbsoluteEditLinkWithoutSuffix, operation.BindingParameter.ParameterType.FullName);
                return(RequestUriProcessor.AppendUnescapedSegment(editLinkWithBindingType, targetSegment));
            }

            return(RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.AbsoluteEditLink, targetSegment));
        }
Пример #5
0
        private ODataStreamReferenceValue GetNamedStreamPropertyValue(object element, ResourceProperty namedStreamProperty, Uri relativeUri)
        {
            string str;
            Uri    uri;
            string str2;

            base.Service.StreamProvider.GetStreamDescription(element, namedStreamProperty, base.Service.OperationContext, out str, out uri, out str2);
            ODataStreamReferenceValue value2 = new ODataStreamReferenceValue {
                ContentType = str2,
                EditLink    = RequestUriProcessor.AppendUnescapedSegment(relativeUri, namedStreamProperty.Name)
            };

            if (!string.IsNullOrEmpty(str))
            {
                value2.ETag = str;
            }
            value2.ReadLink = uri;
            return(value2);
        }
Пример #6
0
        /// <summary>
        /// Creates the navigation link for the given navigation property.
        /// </summary>
        /// <param name="entityToSerialize">Entity that is currently being serialized.</param>
        /// <param name="navigationProperty">The metadata for the navigation property.</param>
        /// <returns>The navigation link for the given property.</returns>
        private ODataNavigationLink GetNavigationLink(EntityToSerialize entityToSerialize, ResourceProperty navigationProperty)
        {
            Debug.Assert(entityToSerialize != null, "entityToSerialize != null");
            Debug.Assert(navigationProperty != null, "navigationProperty != null");

            string navLinkName          = navigationProperty.Name;
            ODataNavigationLink navLink = new ODataNavigationLink
            {
                Name         = navLinkName,
                IsCollection = navigationProperty.Kind == ResourcePropertyKind.ResourceSetReference
            };

            // Always pass the relative uri to the ODatalib. For Json, they will convert the relative uri
            // into absolute uri using the BaseUri property on the ODataWriterSettings. For atom, ODataLib
            // will write the relative uri.
            this.PayloadMetadataPropertyManager.SetUrl(navLink, () => RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.RelativeEditLink, navLinkName));

            if (this.Service.Configuration.DataServiceBehavior.IncludeAssociationLinksInResponse)
            {
                this.PayloadMetadataPropertyManager.SetAssociationLinkUrl(navLink, () => GetAssociationLinkUrl(entityToSerialize, navigationProperty));
            }

            return(navLink);
        }
Пример #7
0
        private void WriteNavigationProperties(IExpandedResult expanded, EntityToSerialize entityToSerialize, bool resourceInstanceInFeed, IEnumerable <ProjectionNode> projectionNodesForCurrentResourceType)
        {
            Debug.Assert(entityToSerialize != null, "entityToSerialize != null");
            Debug.Assert(
                projectionNodesForCurrentResourceType == null ||
                projectionNodesForCurrentResourceType.All(projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(entityToSerialize.ResourceType)),
                "The projection nodes must be filtered to the current resource type only.");

            IEnumerable <ResourceProperty> navProperties =
                projectionNodesForCurrentResourceType == null
                ? this.Provider.GetResourceSerializableProperties(this.CurrentContainer, entityToSerialize.ResourceType).Where(p => p.TypeKind == ResourceTypeKind.EntityType)
                : projectionNodesForCurrentResourceType.Where(p => p.Property != null && p.Property.TypeKind == ResourceTypeKind.EntityType).Select(p1 => p1.Property);

            foreach (ResourceProperty property in navProperties)
            {
                ResourcePropertyInfo navProperty = this.GetNavigationPropertyInfo(expanded, entityToSerialize.Entity, entityToSerialize.ResourceType, property);
                ODataNavigationLink  navLink     = this.GetNavigationLink(entityToSerialize, navProperty.Property);

                // WCF Data Services show performance degradation with JsonLight when entities have > 25 Navgations on writing entries
                // DEVNOTE: for performance reasons, if the link has no content due to the metadata level, and is not expanded
                // then don't tell ODataLib about it at all.
                if (navLink.Url == null && navLink.AssociationLinkUrl == null && !navProperty.Expand)
                {
                    continue;
                }

                var linkArgs = new DataServiceODataWriterNavigationLinkArgs(navLink, this.Service.OperationContext);
                this.dataServicesODataWriter.WriteStart(linkArgs);

                if (navProperty.Expand)
                {
                    object          navPropertyValue          = navProperty.Value;
                    IExpandedResult navPropertyExpandedResult = navPropertyValue as IExpandedResult;
                    object          expandedPropertyValue     =
                        navPropertyExpandedResult != null?
                        GetExpandedElement(navPropertyExpandedResult) :
                            navPropertyValue;

                    bool needPop = this.PushSegmentForProperty(navProperty.Property, entityToSerialize.ResourceType, navProperty.ExpandedNode);

                    // if this.CurrentContainer is null, the target set of the navigation property is hidden.
                    if (this.CurrentContainer != null)
                    {
                        if (navProperty.Property.Kind == ResourcePropertyKind.ResourceSetReference)
                        {
                            IEnumerable enumerable;
                            bool        collection = WebUtil.IsElementIEnumerable(expandedPropertyValue, out enumerable);
                            Debug.Assert(collection, "metadata loading must have ensured that navigation set properties must implement IEnumerable");

                            QueryResultInfo queryResults = new QueryResultInfo(enumerable);
                            try
                            {
                                queryResults.MoveNext();
                                Func <Uri> getNavPropertyRelativeUri = () => RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.RelativeEditLink, navLink.Name);
                                Func <Uri> getNavPropertyAbsoluteUri = () => RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.AbsoluteEditLink, navLink.Name);
                                this.WriteFeedElements(navPropertyExpandedResult, queryResults, navProperty.Property.ResourceType, navLink.Name, getNavPropertyRelativeUri, getNavPropertyAbsoluteUri, false);
                            }
                            finally
                            {
                                // After the navigation property is completely serialized, dispose the property value.
                                WebUtil.Dispose(queryResults);
                            }
                        }
                        else if (WebUtil.IsNullValue(expandedPropertyValue))
                        {
                            // Write a null reference navigation property
                            var entryArgs = new DataServiceODataWriterEntryArgs(null, null, this.Service.OperationContext);
                            this.dataServicesODataWriter.WriteStart(entryArgs);
                            this.dataServicesODataWriter.WriteEnd(entryArgs);
                        }
                        else
                        {
                            this.WriteEntry(navPropertyExpandedResult, expandedPropertyValue, resourceInstanceInFeed, navProperty.Property.ResourceType);
                        }
                    }

                    this.PopSegmentName(needPop);
                }

                this.dataServicesODataWriter.WriteEnd(linkArgs); // end of navigation property
            }
        }
Пример #8
0
        /// <summary>
        /// Gets the association link URL.
        /// </summary>
        /// <param name="entityToSerialize">The entity to serialize.</param>
        /// <param name="navigationProperty">The navigation property.</param>
        /// <returns>The association link url.</returns>
        private static Uri GetAssociationLinkUrl(EntityToSerialize entityToSerialize, ResourceProperty navigationProperty)
        {
            Uri associationLinkUri = RequestUriProcessor.AppendUnescapedSegment(entityToSerialize.SerializedKey.RelativeEditLink, navigationProperty.Name);

            return(RequestUriProcessor.AppendEscapedSegment(associationLinkUri, XmlConstants.UriLinkSegment));
        }
Пример #9
0
 /// <summary>
 /// Wraps a lazy URI with another that will have the given string appended if it is not null.
 /// </summary>
 /// <param name="lazyUri">The lazy URI to wrap.</param>
 /// <param name="suffix">The suffix for the URI.</param>
 /// <returns>A new lazy URI which will have the suffix, or the same instance if the suffix was null.</returns>
 private static SimpleLazy <Uri> AppendLazilyIfNeeded(SimpleLazy <Uri> lazyUri, string suffix)
 {
     return(suffix == null ? lazyUri : new SimpleLazy <Uri>(() => RequestUriProcessor.AppendUnescapedSegment(lazyUri.Value, suffix), false));
 }
Пример #10
0
 internal static Uri AppendEntryToUri(Uri currentUri, string entry)
 {
     return(RequestUriProcessor.AppendUnescapedSegment(currentUri, entry));
 }
Пример #11
0
        private void PopulateODataOperations(object resourceInstance, bool resourceInstanceInFeed, ODataEntry entry, ResourceType actualResourceType)
        {
            Func <OperationWrapper, bool> predicate = null;
            ResourceType resourceType = base.CurrentContainer.ResourceType;
            IEnumerable <OperationWrapper> operationProjections = base.GetOperationProjections();

            if (operationProjections == null)
            {
                operationProjections = base.Service.ActionProvider.GetServiceActionsByBindingParameterType(base.Service.OperationContext, actualResourceType);
            }
            else
            {
                if (predicate == null)
                {
                    predicate = o => o.BindingParameter.ParameterType.IsAssignableFrom(actualResourceType);
                }
                operationProjections = operationProjections.Where <OperationWrapper>(predicate);
            }
            if (operationProjections.Any <OperationWrapper>())
            {
                List <ODataAction> source        = new List <ODataAction>();
                string             containerName = base.Service.Provider.ContainerName;
                foreach (OperationWrapper wrapper in operationProjections)
                {
                    string       text = null;
                    string       actionTitleSegmentByResourceType = wrapper.GetActionTitleSegmentByResourceType(actualResourceType, containerName);
                    ResourceType parameterType = wrapper.BindingParameter.ParameterType;
                    if ((parameterType != resourceType) && resourceType.IsAssignableFrom(parameterType))
                    {
                        text = wrapper.BindingParameter.ParameterType.FullName + "/" + actionTitleSegmentByResourceType;
                    }
                    else
                    {
                        text = actionTitleSegmentByResourceType;
                    }
                    Uri         uri = new Uri(entry.Id, UriKind.RelativeOrAbsolute);
                    Uri         oDataOperationMetadata = base.GetODataOperationMetadata(base.AbsoluteServiceUri, wrapper.Name);
                    Uri         uri3 = RequestUriProcessor.AppendUnescapedSegment(uri, text);
                    ODataAction item = new ODataAction {
                        Title    = wrapper.Name,
                        Metadata = oDataOperationMetadata,
                        Target   = uri3
                    };
                    if (wrapper.OperationParameterBindingKind == OperationParameterBindingKind.Always)
                    {
                        source.Add(item);
                    }
                    else if (base.Service.ActionProvider.AdvertiseServiceAction(base.Service.OperationContext, wrapper, resourceInstance, resourceInstanceInFeed, ref item))
                    {
                        if (item == null)
                        {
                            throw new DataServiceException(500, System.Data.Services.Strings.DataServiceActionProviderWrapper_AdvertiseServiceActionCannotReturnNullActionToSerialize);
                        }
                        source.Add(item);
                    }
                }
                if (source.Any <ODataAction>())
                {
                    entry.Actions = source;
                }
            }
        }