/// <summary>Initializes a new <see cref="PlainXmlDeserializer"/> based on the settings for another one.</summary> /// <param name="reader">Reader for content.</param> /// <param name="deserializer">Parent deserializer.</param> /// <param name="propertiesApplied">Properties already applied based on content</param> internal PlainXmlDeserializer(XmlReader reader, Deserializer deserializer, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied) : base(deserializer) { Debug.Assert(reader != null, "reader != null"); this.xmlReader = reader; Debug.Assert(propertiesApplied != null, "Requires valid collection for applied properties"); this.propertiesApplied = propertiesApplied; this.currentPathPrefix = String.Empty; // this.xmlReaderOwned = false; }
/// <summary> /// Matches the targetSegment with properties already applied and if finds something already applied considers it a match /// </summary> /// <param name="targetSegment">Target segment for which existing property application is checked for</param> /// <param name="propertiesApplied">Properties already applied based on content</param> /// <returns>true if already the property for the current segment has been applied</returns> internal static bool Match(EpmTargetPathSegment targetSegment, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied) { if (!targetSegment.EpmInfo.Attribute.KeepInContent) { return(propertiesApplied.Lookup(targetSegment.EpmInfo.Attribute.SourcePath)); } else { return(true); } }
/// <summary>Reads the current object from the <paramref name="item"/>.</summary> /// <param name="segmentInfo">segmentinfo containing information about the current element that is getting processes</param> /// <param name="topLevel">true if the element currently pointed by the xml reader refers to a top level element</param> /// <param name="item">Item to read from.</param> /// <returns>returns the clr object with the data populated</returns> private object CreateObject(SegmentInfo segmentInfo, bool topLevel, SyndicationItem item) { Debug.Assert(item != null, "item != null"); Debug.Assert(topLevel || !this.Update, "deep updates not supported"); this.RecurseEnter(); object result; // update the object count everytime you encounter a new resource this.CheckAndIncrementObjectCount(); // Process the type annotation. ResourceType currentResourceType = this.GetResourceType(item, segmentInfo.TargetResourceType); if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); } // We have the actual type info from the payload. Update the request/response DSV if any property is FF mapped with KeepInContent=false. this.UpdateAndCheckEpmRequestResponseDSV(currentResourceType, topLevel); // Get a resource cookie from the provider. ResourceSetWrapper container; if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { // Open navigation properties are not supported on OpenTypes. throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segmentInfo.Identifier)); } else { Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); container = segmentInfo.TargetContainer; } DataServiceHostWrapper host = this.Service.OperationContext.Host; if (this.Update) { Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types"); // Only verify ETag if there is going to be some update applied (that's the idea) // In reality: // - for normal entities (V1 compatible) - don't check ETags if there is no content element. (Same as in V1) // - for V2 stuff - check ETags always as we can't tell if there's going to be something modified or not // with EPM properties can be anywhere in the payload and thus even without content there still can be updates // with MLE the properties are not in the content element but in their own element // It's hard to recognize if there's going to be update up front and so this below is an approximation // which seems to be good enough. Note that if we add new ways of handling properties in the content // the condition below might need to change. bool verifyETag = topLevel && (HasContent(item) || currentResourceType.HasEntityPropertyMappings || currentResourceType.IsMediaLinkEntry); bool replaceResource = topLevel && host.AstoriaHttpVerb == AstoriaVerbs.PUT; // if its a top level resource, then it cannot be null result = this.GetObjectFromSegmentInfo(currentResourceType, segmentInfo, verifyETag, topLevel /*checkForNull*/, replaceResource); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Change); } } else { if (segmentInfo.TargetKind == RequestTargetKind.Resource) { DataServiceConfiguration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); } result = this.Updatable.CreateResource(container.Name, currentResourceType.FullName); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Add); } } // Process the content in the entry. EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied = new EpmContentDeSerializer.EpmAppliedPropertyInfo(); this.ApplyProperties(item, currentResourceType, propertiesApplied, result); // Perform application of epm properties here if (currentResourceType.HasEntityPropertyMappings) { new EpmContentDeSerializer(currentResourceType, result).DeSerialize( item, new EpmContentDeSerializer.EpmContentDeserializerState { IsUpdateOperation = this.Update, Updatable = this.Updatable, Service = this.Service, PropertiesApplied = propertiesApplied }); } // Process the links in the entry. foreach (SyndicationLink link in item.Links) { string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); if (null == navigationPropertyName) { continue; } Deserializer.CheckForBindingInPutOperations(host.AstoriaHttpVerb); Debug.Assert(segmentInfo.TargetContainer != null, "segmentInfo.TargetContainer != null"); this.ApplyLink(link, segmentInfo.TargetContainer, currentResourceType, result, navigationPropertyName); } this.RecurseLeave(); return result; }