/// <summary>Applies the properties in the plain XML content to the specified resource.</summary> /// <param name="item">item to read from.</param> /// <param name='resourceType'>Type of resource whose values are being set.</param> /// <param name="propertiesApplied">Properties that have been applied to the <paramref name="resource"/></param> /// <param name='resource'>Target resource.</param> private void ApplyProperties(SyndicationItem item, ResourceType resourceType, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied, object resource) { Debug.Assert(item != null, "item != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(propertiesApplied != null, "propertiesApplied != null"); Debug.Assert(resource != null, "resource != null"); using (XmlReader propertiesFromEntry = GetPropertiesReaderFromEntry(item)) using (XmlReader propertiesFromContent = GetPropertiesReaderFromContent(item)) { XmlReader reader = null; if (resourceType.IsMediaLinkEntry) { if (propertiesFromContent != null) { // The server is expecting a MLE payload, however we found a <m:properties> element under the <atom:content> element. // The client must assumed the resource type is a non-MLE type and serialized as such. // // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on // the server where as in fact the properties element is under the wrong node. throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); } reader = propertiesFromEntry; } else { if (propertiesFromEntry != null) { // The server is expecting a non-MLE payload, however we found a <m:properties> element under the <entry> element. // The client must assumed the resource type is a MLE type and serialized as such. // // We must throw here otherwise the client would falsely assume all the properties are correctly deserialized on // the server where as in fact the properties element is under the wrong node. throw DataServiceException.CreateBadRequestError(Strings.DataServiceException_GeneralError); } reader = propertiesFromContent; } if (reader != null) { reader.ReadStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace); PlainXmlDeserializer.ApplyContent(this, reader, resourceType, resource, propertiesApplied, this.MaxObjectCount); } } }
/// <summary>Applies properties from the reader to the specified resource.</summary> /// <param name="deserializer">Deserializer which is driving the <paramref name="reader"/>.</param> /// <param name='reader'>XmlReader to read from.</param> /// <param name='resourceType'>Type of resource.</param> /// <param name='resource'>Resource to set value on.</param> /// <param name="propertiesApplied">Properties already applied based on content</param> /// <param name="currentObjectCount">current object count for this operation.</param> /// <remarks> /// This method will end as soon as it find something that is not an /// XML element to process. /// </remarks> internal static void ApplyContent(Deserializer deserializer, XmlReader reader, ResourceType resourceType, object resource, EpmContentDeSerializer.EpmAppliedPropertyInfo propertiesApplied, int currentObjectCount) { Debug.Assert(deserializer != null, "deserializer != null"); Debug.Assert(reader != null, "reader != null"); using (PlainXmlDeserializer xml = new PlainXmlDeserializer(reader, deserializer, propertiesApplied)) { // Initialize the new deserializer instance with the current object count xml.UpdateObjectCount(currentObjectCount); // load all the properties xml.ApplyContent(xml.xmlReader, resourceType, resource); // After all the properties have been loaded, initialize the current deserializer value with the object count deserializer.UpdateObjectCount(xml.MaxObjectCount); } }
/// <summary>Reads a typed property from the specified XmlReader.</summary> /// <param name='reader'>XmlReader to read from.</param> /// <param name='propertyName'>Name of property to read.</param> /// <param name='resourceProperty'>resourceProperty whose value is to be read.</param> /// <returns>The instance read, possibly null.</returns> private object ReadPropertyWithType(XmlReader reader, string propertyName, ResourceProperty resourceProperty) { Debug.Assert(reader != null, "reader != null"); Debug.Assert(propertyName != null, "propertyName != null"); ResourceType propertyType = null; // If this is a open property OR we do not have to do type conversion for primitive types, // read the type from the payload. bool readTypeFromWire = resourceProperty == null || (!this.Service.Configuration.EnableTypeConversion && resourceProperty.ResourceType.ResourceTypeKind == ResourceTypeKind.Primitive); if (readTypeFromWire) { propertyType = this.ReadOpenPropertyTypeAttribute(reader); } else { propertyType = resourceProperty.ResourceType; } if (this.propertiesApplied != null) { this.propertiesApplied.AddPropertyToTypeMapItem( this.BuildPropertyPath(propertyName), propertyType.FullName); } object propertyValue; String appliedPropertyName = resourceProperty != null ? resourceProperty.Name : propertyName; switch (propertyType.ResourceTypeKind) { case ResourceTypeKind.ComplexType: this.CheckAndIncrementObjectCount(); bool isNull = HasNullAttributeWithTrueValue(reader); if (this.propertiesApplied != null) { this.propertiesApplied.AddAppliedProperty(this.BuildPropertyPath(appliedPropertyName), isNull); } if (isNull) { propertyValue = null; } else { propertyValue = this.Updatable.CreateResource(null, propertyType.FullName); if (!reader.IsEmptyElement) { // Step inside the complex type, apply its properties, and pop back out. using (XmlReader propertyReader = reader.ReadSubtree()) { if (!WebUtil.XmlReaderEnsureElement(propertyReader)) { throw DataServiceException.CreateBadRequestError( Strings.PlainXml_PropertyLacksElement(propertyName)); } propertyReader.ReadStartElement(); String savedPath = this.currentPathPrefix; this.currentPathPrefix = String.IsNullOrEmpty(this.currentPathPrefix) ? appliedPropertyName : this.currentPathPrefix + "/" + appliedPropertyName; ApplyContent(propertyReader, propertyType, propertyValue); this.currentPathPrefix = savedPath; } Debug.Assert( reader.NodeType == XmlNodeType.EndElement, "reader.NodeType == XmlNodeType.EndElement -- otherwise ReadSubtree left outer read in incorrect position."); } } break; case ResourceTypeKind.EntityType: throw DataServiceException.CreateBadRequestError( Strings.PlainXml_NavigationPropertyNotSupported(propertyName)); default: Debug.Assert( propertyType.ResourceTypeKind == ResourceTypeKind.Primitive, "property.TypeKind == ResourceTypeKind.Primitive -- metadata shouldn't return " + propertyType.ResourceTypeKind); propertyValue = ReadElementString(reader, propertyName); // We need to convert the type to the wire type. Conversion to the property type happens in Deserializer.SetValue method. if (readTypeFromWire) { propertyValue = PlainXmlDeserializer.ConvertValuesForXml(propertyValue, propertyName, propertyType.InstanceType); } if (this.propertiesApplied != null) { this.propertiesApplied.AddAppliedProperty(this.BuildPropertyPath(appliedPropertyName), false); } break; } return(propertyValue); }
/// <summary> /// Creates a new <see cref="Deserializer"/> for the specified stream. /// </summary> /// <param name="description">description about the request uri.</param> /// <param name="dataService">Data service for which the deserializer will act.</param> /// <param name="update">indicates whether this is a update operation or not</param> /// <param name="tracker">Tracker to use for modifications.</param> /// <returns>A new instance of <see cref="Deserializer"/>.</returns> internal static Deserializer CreateDeserializer(RequestDescription description, IDataService dataService, bool update, UpdateTracker tracker) { string mimeType; System.Text.Encoding encoding; DataServiceHostWrapper host = dataService.OperationContext.Host; HttpProcessUtility.ReadContentType(host.RequestContentType, out mimeType, out encoding); ContentFormat requestFormat = WebUtil.SelectRequestFormat(mimeType, description); Stream requestStream = host.RequestStream; Debug.Assert(requestStream != null, "requestStream != null"); Debug.Assert(tracker != null, "Change tracker must always be created."); Deserializer deserializer = null; Debug.Assert( (!update /*POST*/ && dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.POST) || (update /*PUT,MERGE*/ && (dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.MERGE || dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.PUT)), "For PUT and MERGE, update must be true; for POST, update must be false"); switch (requestFormat) { case ContentFormat.Json: deserializer = new JsonDeserializer( requestStream, encoding, update, dataService, tracker); break; case ContentFormat.Atom: SyndicationFormatterFactory factory = new Atom10FormatterFactory(); deserializer = new SyndicationDeserializer( requestStream, // stream encoding, // encoding dataService, // dataService update, factory, tracker); // factory break; case ContentFormat.PlainXml: deserializer = new PlainXmlDeserializer( requestStream, encoding, dataService, update, tracker); break; default: throw new DataServiceException(415, Strings.BadRequest_UnsupportedRequestContentType(host.RequestContentType)); } Debug.Assert(deserializer != null, "deserializer != null"); return deserializer; }