/// <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); }
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 }); }
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); }
/// <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)); }
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); }
/// <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); }
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 } }
/// <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)); }
/// <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)); }
internal static Uri AppendEntryToUri(Uri currentUri, string entry) { return(RequestUriProcessor.AppendUnescapedSegment(currentUri, entry)); }
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; } } }