Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / SyndicationDeserializer.cs / 1 / SyndicationDeserializer.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a deserializer for atom content structured as // syndication items or feeds. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Serializers { #region Namespaces. using System; using System.Collections.Generic; using System.Data.Services.Providers; using System.Diagnostics; using System.Linq; using System.IO; using System.ServiceModel.Syndication; using System.Text; using System.Xml; #endregion Namespaces. ///Provides a deserializer for structured content. internal class SyndicationDeserializer : Deserializer { ///Factory for syndication formatting objects. private readonly SyndicationFormatterFactory factory; ///reader to read xml from the request stream private readonly XmlReader xmlReader; ///Initializes a new /// Input stream reader from which ATOM content must be read. /// Encoding to use for the stream (null to auto-discover). /// Data service for which the deserializer will act. /// indicates whether this is a update operation or not /// Factory for formatter objects. /// Tracker to use for modifications. internal SyndicationDeserializer(Stream stream, Encoding encoding, IDataService dataService, bool update, SyndicationFormatterFactory factory, UpdateTracker tracker) : base(update, dataService, tracker) { Debug.Assert(stream != null, "stream != null"); Debug.Assert(factory != null, "factory != null"); this.factory = factory; this.xmlReader = factory.CreateReader(stream, encoding); } ///for the specified stream. /// Indicates the various form of data in the inline xml element /// private enum LinkContent { ///If the link element didn't not contain an inline element at all. NoInlineElementSpecified, ///If the link element contained an empty inline element. EmptyInlineElementSpecified, ///If the inline element under the link element contained some data. InlineElementContainsData } ///returns the content format for the deserializer protected override ContentFormat ContentFormat { get { return ContentFormat.Atom; } } ////// Assumes the payload to represent a single object and processes accordingly /// /// info about the object being created ///the newly formed object that the payload represents protected override object CreateSingleObject(SegmentInfo segmentInfo) { SyndicationItem item = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), this.xmlReader); return this.CreateObject(segmentInfo, true /*topLevel*/, item); } ///Provides an opportunity to clean-up resources. /// /// Whether the call is being made from an explicit call to /// IDisposable.Dispose() rather than through the finalizer. /// protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { this.xmlReader.Close(); } } ////// Get the resource referred by the uri in the payload /// ///resource referred by the uri in the payload. protected override string GetLinkUriFromPayload() { throw Error.NotImplemented(); } ///Checks whether the specified item has a payload. /// Item to check. ///true if the item has content or links specified; false otherwise. private static bool HasContent(SyndicationItem item) { return item.Content != null || item.Links.Count > 0; } ///Gets the text for the type annotated on the specified /// Item to read type from. ///. The text for the type annotated on the specified item; null if none is set. private static string SyndicationItemGetType(SyndicationItem item) { Debug.Assert(item != null, "item != null"); SyndicationCategory category = item.Categories.Where(c => c.Scheme == XmlConstants.DataWebSchemeNamespace).FirstOrDefault(); return (category == null) ? null : category.Name; } ///Reads a SyndicationFeed object from the specified XmlReader. /// Formatter to use when reading content. /// Read to read feed from. ///A new SyndicationFeed instance. private static SyndicationFeed ReadSyndicationFeed(SyndicationFeedFormatter formatter, XmlReader reader) { Debug.Assert(formatter != null, "formatter != null"); Debug.Assert(reader != null, "reader != null"); try { formatter.ReadFrom(reader); } catch (XmlException exception) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingFeed(exception.Message), exception); } Debug.Assert(formatter.Feed != null, "formatter.Feed != null"); return formatter.Feed; } ///Reads a SyndicationItem object from the specified XmlReader. /// Formatter to use when reading content. /// Read to read feed from. ///A new SyndicationItem instance. private static SyndicationItem ReadSyndicationItem(SyndicationItemFormatter formatter, XmlReader reader) { Debug.Assert(formatter != null, "formatter != null"); Debug.Assert(reader != null, "reader != null"); try { formatter.ReadFrom(reader); } catch (XmlException exception) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingEntry(exception.Message), exception); } Debug.Assert(formatter.Item != null, "formatter.Item != null"); return formatter.Item; } ////// Read the link media type and validate for non open property types /// /// media type as specified on the link element. /// property which the link represents. ///returns the type parameters specified in the media link. private static string ValidateTypeParameterForNonOpenTypeProperties(string mediaType, ResourceProperty property) { string typeParameterValue = null; if (!String.IsNullOrEmpty(mediaType)) { string mime; Encoding encoding; KeyValuePair[] contentTypeParameters = HttpProcessUtility.ReadContentType(mediaType, out mime, out encoding); if (mime != XmlConstants.MimeApplicationAtom) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MimeTypeMustBeApplicationAtom(mime, XmlConstants.MimeApplicationAtom)); } // If the type parameter is specified, make sure its correct. We do the validation for known properties here // and for open-properties, the validation is done if the link is expanded. Otherwise, there is no good way of // doing the validation. typeParameterValue = HttpProcessUtility.GetParameterValue(contentTypeParameters, XmlConstants.AtomTypeAttributeName); if (!String.IsNullOrEmpty(typeParameterValue) && property != null) { if (property.Kind == ResourcePropertyKind.ResourceReference) { if (typeParameterValue != XmlConstants.AtomEntryElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); } } else if (typeParameterValue != XmlConstants.AtomFeedElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName)); } } } return typeParameterValue; } /// Applies the properties in the plain XML content to the specified resource. /// Content to read values from. /// Type of resource whose values are being set. /// Target resource. private void ApplyContent(XmlSyndicationContent content, ResourceType resourceType, object resource) { Debug.Assert(content != null, "content != null"); using (XmlReader reader = content.GetReaderAtContent()) { WebUtil.XmlReaderEnsureElement(reader); Debug.Assert( reader.NodeType == XmlNodeType.Element, reader.NodeType.ToString() + " == XmlNodeType.Element -- otherwise XmlSyndicationContent didn't see a 'content' tag"); reader.ReadStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); reader.ReadStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace); PlainXmlDeserializer.ApplyContent(this, reader, resourceType, resource, this.MaxObjectCount); } } ///Reads the current object from the /// segmentinfo containing information about the current element that is getting processes /// true if the element currently pointed by the xml reader refers to a top level element /// Item to read from. ///. returns the clr object with the data populated 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.TargetElementType); if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); } // Get a resource cookie from the provider. ResourceContainer container; #if ASTORIA_OPEN_OBJECT if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { container = this.Service.Provider.GetContainerForResourceType(currentResourceType.Type); } else #endif { Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); container = segmentInfo.TargetContainer; } if (this.Update) { Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types"); bool verifyETag = topLevel && HasContent(item); bool replaceResource = topLevel && this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT; // if its a top level resource, then it cannot be null result = this.CreateObjectFromUri(currentResourceType, segmentInfo, (RequestDescription)null, verifyETag, topLevel /*checkForNull*/, replaceResource); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Change); } } else { if (segmentInfo.TargetKind == RequestTargetKind.Resource) { this.Service.Configuration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); } result = this.Service.Provider.CreateResource(container.Name, currentResourceType.FullName); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Add); } } // Process the content in the entry. if (item.Content != null) { string contentType = item.Content.Type; if (contentType != XmlConstants.MimeApplicationXml) { throw DataServiceException.CreateBadRequestError( Strings.Syndication_EntryContentTypeUnsupported(contentType)); } XmlSyndicationContent itemContent = item.Content as XmlSyndicationContent; Debug.Assert(itemContent != null, "itemContent != null -- otherwise formatter created the wrong type."); this.ApplyContent(itemContent, currentResourceType, result); } // Process the links in the entry. foreach (SyndicationLink link in item.Links) { string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); if (null == navigationPropertyName) { continue; } Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb); this.ApplyLink(link, currentResourceType, result, navigationPropertyName); } this.RecurseLeave(); return result; } ///Applies the information from a link to the specified resource. /// LinkDescriptor with information to apply. /// Type for the target resource. /// Target resource to which information will be applied. /// Name of the property that this link represents. private void ApplyLink(SyndicationLink link, ResourceType resourceType, object resource, string propertyName) { Debug.Assert(link != null, "link != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resource != null, "resource != null"); ResourceProperty property = resourceType.TryResolvePropertyName(propertyName); if ( #if ASTORIA_OPEN_OBJECT (property == null && resourceType.OpenTypeKind != OpenTypeKind.CompletelyOpen) || #else property == null || #endif (property != null && property.TypeKind != ResourceTypeKind.EntityType)) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidNavigationPropertyName(propertyName, resourceType.FullName)); } string typeParameterValue = ValidateTypeParameterForNonOpenTypeProperties(link.MediaType, property); LinkContent linkContent = this.HandleLinkContent(link, resource, property, typeParameterValue, propertyName); #region Handle bind/unbind operation // If the href was specified empty or an empty inline element was specified, then we will set the // reference to null - this helps in overrriding if there was a default non-value for this property // else if only link element was specified, and then href points to a single result, then we will // perform a bind operation if ((linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && String.IsNullOrEmpty(link.Uri.OriginalString)) || linkContent == LinkContent.EmptyInlineElementSpecified) { // update the object count when you are performing a bind operation this.CheckAndIncrementObjectCount(); if (property != null && property.Kind == ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); } // For open properties, we will assume that this is a reference property and set it to null this.Service.Provider.SetReference(resource, propertyName, null); } else if (linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && !String.IsNullOrEmpty(link.Uri.OriginalString)) { // update the object count when you are performing a bind operation this.CheckAndIncrementObjectCount(); // If the link points to a reference navigation property, then update the link Uri referencedUri = RequestUriProcessor.GetAbsoluteUriFromReference(link.Uri.OriginalString, this.Service.RequestParams); RequestDescription description = RequestUriProcessor.ProcessRequestUri(referencedUri, this.Service); if (!description.IsSingleResult) { if (property != null && property.Kind == ResourcePropertyKind.ResourceReference) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_LinkHrefMustReferToSingleResource(propertyName)); } return; } // no need to check for null. For collection properties, they can never be null and that // check has been added below. For reference properties, if they are null, it means unbind // and hence no need to check for null. object propertyItem = CreateObjectFromUri(null, null, description, false /*verifyETag*/, false /*checkForNull*/, false /*replaceResource*/); if (property != null) { if (property.Kind == ResourcePropertyKind.ResourceReference) { this.Service.Provider.SetReference(resource, propertyName, propertyItem); } else { WebUtil.CheckResourceExists(propertyItem != null, description.LastSegmentInfo.Identifier); this.Service.Provider.AddReferenceToCollection(resource, propertyName, propertyItem); } } else if (typeParameterValue == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MissingTypeParameterOnLinkElement(propertyName)); } else if (typeParameterValue == XmlConstants.AtomEntryElementName) { this.Service.Provider.SetReference(resource, propertyName, propertyItem); } else { if (typeParameterValue != XmlConstants.AtomFeedElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterInTypeAttributeInLink(propertyName, typeParameterValue)); } WebUtil.CheckResourceExists(propertyItem != null, description.LastSegmentInfo.Identifier); this.Service.Provider.AddReferenceToCollection(resource, propertyName, propertyItem); } } #endregion Handle bind/unbind operation } ///Gets the type attribute and resolves the type. /// Item from which type attribute needs to be read /// Expected base type for the item. ///Resolved type. private ResourceType GetResourceType(SyndicationItem item, Type expectedType) { Debug.Assert(item != null, "item != null"); string typeName = SyndicationItemGetType(item); ResourceType resourceType; // If the type is not specified in the payload, we assume the type to be the expected type if (String.IsNullOrEmpty(typeName)) { // check if the expected type takes part in inheritance resourceType = this.Service.Provider.GetResourceType(expectedType); if (resourceType.HasDerivedTypes) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance); } } else { // Otherwise, try and resolve the name specified in the payload resourceType = this.Service.Provider.TryResolveTypeName(typeName); if (resourceType == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName)); } } return resourceType; } ////// Handle the contents under the link element /// /// syndication link element /// parent resource which contains the link. /// property representing the link. /// type parameter value as specified in the type attribute. /// name of the property that this link represents. ///returns whether there are child elements under link element. private LinkContent HandleLinkContent( SyndicationLink link, object parentResource, ResourceProperty property, string typeParameterValue, string propertyName) { Debug.Assert(parentResource != null, "parent resource cannot be null"); Debug.Assert(link != null, "link != null"); LinkContent linkContent = LinkContent.NoInlineElementSpecified; foreach (var e in link.ElementExtensions) { // link can contain other elements apart from the inline elements. if (e.OuterNamespace != XmlConstants.DataWebMetadataNamespace || e.OuterName != XmlConstants.AtomInlineElementName) { continue; } // Deep payload cannot be specified for update if (this.Update) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported); } linkContent = LinkContent.EmptyInlineElementSpecified; using (XmlReader linkReader = e.GetReader()) { while (linkReader.Read()) { if (linkReader.NodeType == XmlNodeType.Element) { string elementName = linkReader.LocalName; string namespaceUri = linkReader.NamespaceURI; if (namespaceUri != XmlConstants.AtomNamespace) { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_InlineElementMustContainValidElement( elementName, XmlConstants.AtomInlineElementName, XmlConstants.AtomFeedElementName, XmlConstants.AtomEntryElementName)); } linkContent = LinkContent.InlineElementContainsData; if (elementName == XmlConstants.AtomEntryElementName) { if (property != null) { if (property.Kind != ResourcePropertyKind.ResourceReference) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_EntryElementForReferenceProperties(e.OuterName, propertyName)); } } else if (typeParameterValue != null && typeParameterValue != elementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); } // Make sure if the media type is specified. If its specified, it should better be link SyndicationItem propertyItem; propertyItem = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), linkReader); SegmentInfo propertySegment = CreateSegment(property, propertyName, true /* singleResult */); object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, propertyItem); this.Service.Provider.SetReference(parentResource, propertyName, propertyValue); } else if (elementName == XmlConstants.AtomFeedElementName) { if (property != null) { if (property.Kind != ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_FeedElementForCollections(e.OuterName, propertyName)); } } else if (typeParameterValue != null && typeParameterValue != elementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName)); } SyndicationFeed propertyFeed; propertyFeed = ReadSyndicationFeed(this.factory.CreateSyndicationFeedFormatter(), linkReader); SegmentInfo propertySegment = CreateSegment(property, propertyName, false /* singleResult */); foreach (SyndicationItem item in propertyFeed.Items) { object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, item); if (propertyValue == null) { if (propertySegment.ProjectedProperty != null && propertySegment.ProjectedProperty.Kind == ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); } } Debug.Assert( #if ASTORIA_OPEN_OBJECT propertySegment.TargetKind == RequestTargetKind.OpenProperty || #endif (propertySegment.TargetSource == RequestTargetSource.Property && propertySegment.TargetKind == RequestTargetKind.Resource && propertySegment.SingleResult == false), "must be navigation set property or open property"); this.Service.Provider.AddReferenceToCollection(parentResource, propertyName, propertyValue); } } else { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_InlineElementMustContainValidElement( elementName, XmlConstants.AtomInlineElementName, XmlConstants.AtomFeedElementName, XmlConstants.AtomEntryElementName)); } } } } } return linkContent; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a deserializer for atom content structured as // syndication items or feeds. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Serializers { #region Namespaces. using System; using System.Collections.Generic; using System.Data.Services.Providers; using System.Diagnostics; using System.Linq; using System.IO; using System.ServiceModel.Syndication; using System.Text; using System.Xml; #endregion Namespaces. ///Provides a deserializer for structured content. internal class SyndicationDeserializer : Deserializer { ///Factory for syndication formatting objects. private readonly SyndicationFormatterFactory factory; ///reader to read xml from the request stream private readonly XmlReader xmlReader; ///Initializes a new /// Input stream reader from which ATOM content must be read. /// Encoding to use for the stream (null to auto-discover). /// Data service for which the deserializer will act. /// indicates whether this is a update operation or not /// Factory for formatter objects. /// Tracker to use for modifications. internal SyndicationDeserializer(Stream stream, Encoding encoding, IDataService dataService, bool update, SyndicationFormatterFactory factory, UpdateTracker tracker) : base(update, dataService, tracker) { Debug.Assert(stream != null, "stream != null"); Debug.Assert(factory != null, "factory != null"); this.factory = factory; this.xmlReader = factory.CreateReader(stream, encoding); } ///for the specified stream. /// Indicates the various form of data in the inline xml element /// private enum LinkContent { ///If the link element didn't not contain an inline element at all. NoInlineElementSpecified, ///If the link element contained an empty inline element. EmptyInlineElementSpecified, ///If the inline element under the link element contained some data. InlineElementContainsData } ///returns the content format for the deserializer protected override ContentFormat ContentFormat { get { return ContentFormat.Atom; } } ////// Assumes the payload to represent a single object and processes accordingly /// /// info about the object being created ///the newly formed object that the payload represents protected override object CreateSingleObject(SegmentInfo segmentInfo) { SyndicationItem item = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), this.xmlReader); return this.CreateObject(segmentInfo, true /*topLevel*/, item); } ///Provides an opportunity to clean-up resources. /// /// Whether the call is being made from an explicit call to /// IDisposable.Dispose() rather than through the finalizer. /// protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { this.xmlReader.Close(); } } ////// Get the resource referred by the uri in the payload /// ///resource referred by the uri in the payload. protected override string GetLinkUriFromPayload() { throw Error.NotImplemented(); } ///Checks whether the specified item has a payload. /// Item to check. ///true if the item has content or links specified; false otherwise. private static bool HasContent(SyndicationItem item) { return item.Content != null || item.Links.Count > 0; } ///Gets the text for the type annotated on the specified /// Item to read type from. ///. The text for the type annotated on the specified item; null if none is set. private static string SyndicationItemGetType(SyndicationItem item) { Debug.Assert(item != null, "item != null"); SyndicationCategory category = item.Categories.Where(c => c.Scheme == XmlConstants.DataWebSchemeNamespace).FirstOrDefault(); return (category == null) ? null : category.Name; } ///Reads a SyndicationFeed object from the specified XmlReader. /// Formatter to use when reading content. /// Read to read feed from. ///A new SyndicationFeed instance. private static SyndicationFeed ReadSyndicationFeed(SyndicationFeedFormatter formatter, XmlReader reader) { Debug.Assert(formatter != null, "formatter != null"); Debug.Assert(reader != null, "reader != null"); try { formatter.ReadFrom(reader); } catch (XmlException exception) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingFeed(exception.Message), exception); } Debug.Assert(formatter.Feed != null, "formatter.Feed != null"); return formatter.Feed; } ///Reads a SyndicationItem object from the specified XmlReader. /// Formatter to use when reading content. /// Read to read feed from. ///A new SyndicationItem instance. private static SyndicationItem ReadSyndicationItem(SyndicationItemFormatter formatter, XmlReader reader) { Debug.Assert(formatter != null, "formatter != null"); Debug.Assert(reader != null, "reader != null"); try { formatter.ReadFrom(reader); } catch (XmlException exception) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_ErrorReadingEntry(exception.Message), exception); } Debug.Assert(formatter.Item != null, "formatter.Item != null"); return formatter.Item; } ////// Read the link media type and validate for non open property types /// /// media type as specified on the link element. /// property which the link represents. ///returns the type parameters specified in the media link. private static string ValidateTypeParameterForNonOpenTypeProperties(string mediaType, ResourceProperty property) { string typeParameterValue = null; if (!String.IsNullOrEmpty(mediaType)) { string mime; Encoding encoding; KeyValuePair[] contentTypeParameters = HttpProcessUtility.ReadContentType(mediaType, out mime, out encoding); if (mime != XmlConstants.MimeApplicationAtom) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MimeTypeMustBeApplicationAtom(mime, XmlConstants.MimeApplicationAtom)); } // If the type parameter is specified, make sure its correct. We do the validation for known properties here // and for open-properties, the validation is done if the link is expanded. Otherwise, there is no good way of // doing the validation. typeParameterValue = HttpProcessUtility.GetParameterValue(contentTypeParameters, XmlConstants.AtomTypeAttributeName); if (!String.IsNullOrEmpty(typeParameterValue) && property != null) { if (property.Kind == ResourcePropertyKind.ResourceReference) { if (typeParameterValue != XmlConstants.AtomEntryElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); } } else if (typeParameterValue != XmlConstants.AtomFeedElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName)); } } } return typeParameterValue; } /// Applies the properties in the plain XML content to the specified resource. /// Content to read values from. /// Type of resource whose values are being set. /// Target resource. private void ApplyContent(XmlSyndicationContent content, ResourceType resourceType, object resource) { Debug.Assert(content != null, "content != null"); using (XmlReader reader = content.GetReaderAtContent()) { WebUtil.XmlReaderEnsureElement(reader); Debug.Assert( reader.NodeType == XmlNodeType.Element, reader.NodeType.ToString() + " == XmlNodeType.Element -- otherwise XmlSyndicationContent didn't see a 'content' tag"); reader.ReadStartElement(XmlConstants.AtomContentElementName, XmlConstants.AtomNamespace); reader.ReadStartElement(XmlConstants.AtomPropertiesElementName, XmlConstants.DataWebMetadataNamespace); PlainXmlDeserializer.ApplyContent(this, reader, resourceType, resource, this.MaxObjectCount); } } ///Reads the current object from the /// segmentinfo containing information about the current element that is getting processes /// true if the element currently pointed by the xml reader refers to a top level element /// Item to read from. ///. returns the clr object with the data populated 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.TargetElementType); if (currentResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_OnlyEntityTypesMustBeSpecifiedInEntryElement(currentResourceType.FullName)); } // Get a resource cookie from the provider. ResourceContainer container; #if ASTORIA_OPEN_OBJECT if (segmentInfo.TargetKind == RequestTargetKind.OpenProperty) { container = this.Service.Provider.GetContainerForResourceType(currentResourceType.Type); } else #endif { Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "segmentInfo.TargetKind == RequestTargetKind.Resource"); container = segmentInfo.TargetContainer; } if (this.Update) { Debug.Assert(currentResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "only expecting entity types"); bool verifyETag = topLevel && HasContent(item); bool replaceResource = topLevel && this.Service.RequestParams.AstoriaHttpVerb == AstoriaVerbs.PUT; // if its a top level resource, then it cannot be null result = this.CreateObjectFromUri(currentResourceType, segmentInfo, (RequestDescription)null, verifyETag, topLevel /*checkForNull*/, replaceResource); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Change); } } else { if (segmentInfo.TargetKind == RequestTargetKind.Resource) { this.Service.Configuration.CheckResourceRights(segmentInfo.TargetContainer, EntitySetRights.WriteAppend); } result = this.Service.Provider.CreateResource(container.Name, currentResourceType.FullName); if (this.Tracker != null) { this.Tracker.TrackAction(result, container, UpdateOperations.Add); } } // Process the content in the entry. if (item.Content != null) { string contentType = item.Content.Type; if (contentType != XmlConstants.MimeApplicationXml) { throw DataServiceException.CreateBadRequestError( Strings.Syndication_EntryContentTypeUnsupported(contentType)); } XmlSyndicationContent itemContent = item.Content as XmlSyndicationContent; Debug.Assert(itemContent != null, "itemContent != null -- otherwise formatter created the wrong type."); this.ApplyContent(itemContent, currentResourceType, result); } // Process the links in the entry. foreach (SyndicationLink link in item.Links) { string navigationPropertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(link.RelationshipType); if (null == navigationPropertyName) { continue; } Deserializer.CheckForBindingInPutOperations(this.Service.RequestParams.AstoriaHttpVerb); this.ApplyLink(link, currentResourceType, result, navigationPropertyName); } this.RecurseLeave(); return result; } ///Applies the information from a link to the specified resource. /// LinkDescriptor with information to apply. /// Type for the target resource. /// Target resource to which information will be applied. /// Name of the property that this link represents. private void ApplyLink(SyndicationLink link, ResourceType resourceType, object resource, string propertyName) { Debug.Assert(link != null, "link != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resource != null, "resource != null"); ResourceProperty property = resourceType.TryResolvePropertyName(propertyName); if ( #if ASTORIA_OPEN_OBJECT (property == null && resourceType.OpenTypeKind != OpenTypeKind.CompletelyOpen) || #else property == null || #endif (property != null && property.TypeKind != ResourceTypeKind.EntityType)) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidNavigationPropertyName(propertyName, resourceType.FullName)); } string typeParameterValue = ValidateTypeParameterForNonOpenTypeProperties(link.MediaType, property); LinkContent linkContent = this.HandleLinkContent(link, resource, property, typeParameterValue, propertyName); #region Handle bind/unbind operation // If the href was specified empty or an empty inline element was specified, then we will set the // reference to null - this helps in overrriding if there was a default non-value for this property // else if only link element was specified, and then href points to a single result, then we will // perform a bind operation if ((linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && String.IsNullOrEmpty(link.Uri.OriginalString)) || linkContent == LinkContent.EmptyInlineElementSpecified) { // update the object count when you are performing a bind operation this.CheckAndIncrementObjectCount(); if (property != null && property.Kind == ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); } // For open properties, we will assume that this is a reference property and set it to null this.Service.Provider.SetReference(resource, propertyName, null); } else if (linkContent == LinkContent.NoInlineElementSpecified && link.Uri != null && !String.IsNullOrEmpty(link.Uri.OriginalString)) { // update the object count when you are performing a bind operation this.CheckAndIncrementObjectCount(); // If the link points to a reference navigation property, then update the link Uri referencedUri = RequestUriProcessor.GetAbsoluteUriFromReference(link.Uri.OriginalString, this.Service.RequestParams); RequestDescription description = RequestUriProcessor.ProcessRequestUri(referencedUri, this.Service); if (!description.IsSingleResult) { if (property != null && property.Kind == ResourcePropertyKind.ResourceReference) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_LinkHrefMustReferToSingleResource(propertyName)); } return; } // no need to check for null. For collection properties, they can never be null and that // check has been added below. For reference properties, if they are null, it means unbind // and hence no need to check for null. object propertyItem = CreateObjectFromUri(null, null, description, false /*verifyETag*/, false /*checkForNull*/, false /*replaceResource*/); if (property != null) { if (property.Kind == ResourcePropertyKind.ResourceReference) { this.Service.Provider.SetReference(resource, propertyName, propertyItem); } else { WebUtil.CheckResourceExists(propertyItem != null, description.LastSegmentInfo.Identifier); this.Service.Provider.AddReferenceToCollection(resource, propertyName, propertyItem); } } else if (typeParameterValue == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MissingTypeParameterOnLinkElement(propertyName)); } else if (typeParameterValue == XmlConstants.AtomEntryElementName) { this.Service.Provider.SetReference(resource, propertyName, propertyItem); } else { if (typeParameterValue != XmlConstants.AtomFeedElementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterInTypeAttributeInLink(propertyName, typeParameterValue)); } WebUtil.CheckResourceExists(propertyItem != null, description.LastSegmentInfo.Identifier); this.Service.Provider.AddReferenceToCollection(resource, propertyName, propertyItem); } } #endregion Handle bind/unbind operation } ///Gets the type attribute and resolves the type. /// Item from which type attribute needs to be read /// Expected base type for the item. ///Resolved type. private ResourceType GetResourceType(SyndicationItem item, Type expectedType) { Debug.Assert(item != null, "item != null"); string typeName = SyndicationItemGetType(item); ResourceType resourceType; // If the type is not specified in the payload, we assume the type to be the expected type if (String.IsNullOrEmpty(typeName)) { // check if the expected type takes part in inheritance resourceType = this.Service.Provider.GetResourceType(expectedType); if (resourceType.HasDerivedTypes) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance); } } else { // Otherwise, try and resolve the name specified in the payload resourceType = this.Service.Provider.TryResolveTypeName(typeName); if (resourceType == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName)); } } return resourceType; } ////// Handle the contents under the link element /// /// syndication link element /// parent resource which contains the link. /// property representing the link. /// type parameter value as specified in the type attribute. /// name of the property that this link represents. ///returns whether there are child elements under link element. private LinkContent HandleLinkContent( SyndicationLink link, object parentResource, ResourceProperty property, string typeParameterValue, string propertyName) { Debug.Assert(parentResource != null, "parent resource cannot be null"); Debug.Assert(link != null, "link != null"); LinkContent linkContent = LinkContent.NoInlineElementSpecified; foreach (var e in link.ElementExtensions) { // link can contain other elements apart from the inline elements. if (e.OuterNamespace != XmlConstants.DataWebMetadataNamespace || e.OuterName != XmlConstants.AtomInlineElementName) { continue; } // Deep payload cannot be specified for update if (this.Update) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_DeepUpdateNotSupported); } linkContent = LinkContent.EmptyInlineElementSpecified; using (XmlReader linkReader = e.GetReader()) { while (linkReader.Read()) { if (linkReader.NodeType == XmlNodeType.Element) { string elementName = linkReader.LocalName; string namespaceUri = linkReader.NamespaceURI; if (namespaceUri != XmlConstants.AtomNamespace) { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_InlineElementMustContainValidElement( elementName, XmlConstants.AtomInlineElementName, XmlConstants.AtomFeedElementName, XmlConstants.AtomEntryElementName)); } linkContent = LinkContent.InlineElementContainsData; if (elementName == XmlConstants.AtomEntryElementName) { if (property != null) { if (property.Kind != ResourcePropertyKind.ResourceReference) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_EntryElementForReferenceProperties(e.OuterName, propertyName)); } } else if (typeParameterValue != null && typeParameterValue != elementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomEntryElementName)); } // Make sure if the media type is specified. If its specified, it should better be link SyndicationItem propertyItem; propertyItem = ReadSyndicationItem(this.factory.CreateSyndicationItemFormatter(), linkReader); SegmentInfo propertySegment = CreateSegment(property, propertyName, true /* singleResult */); object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, propertyItem); this.Service.Provider.SetReference(parentResource, propertyName, propertyValue); } else if (elementName == XmlConstants.AtomFeedElementName) { if (property != null) { if (property.Kind != ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError(Strings.Syndication_FeedElementForCollections(e.OuterName, propertyName)); } } else if (typeParameterValue != null && typeParameterValue != elementName) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeParameterSpecifiedInMimeType(typeParameterValue, XmlConstants.AtomFeedElementName)); } SyndicationFeed propertyFeed; propertyFeed = ReadSyndicationFeed(this.factory.CreateSyndicationFeedFormatter(), linkReader); SegmentInfo propertySegment = CreateSegment(property, propertyName, false /* singleResult */); foreach (SyndicationItem item in propertyFeed.Items) { object propertyValue = this.CreateObject(propertySegment, false /* topLevel */, item); if (propertyValue == null) { if (propertySegment.ProjectedProperty != null && propertySegment.ProjectedProperty.Kind == ResourcePropertyKind.ResourceSetReference) { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_CannotSetCollectionsToNull(propertyName)); } } Debug.Assert( #if ASTORIA_OPEN_OBJECT propertySegment.TargetKind == RequestTargetKind.OpenProperty || #endif (propertySegment.TargetSource == RequestTargetSource.Property && propertySegment.TargetKind == RequestTargetKind.Resource && propertySegment.SingleResult == false), "must be navigation set property or open property"); this.Service.Provider.AddReferenceToCollection(parentResource, propertyName, propertyValue); } } else { throw DataServiceException.CreateBadRequestError( Strings.BadRequest_InlineElementMustContainValidElement( elementName, XmlConstants.AtomInlineElementName, XmlConstants.AtomFeedElementName, XmlConstants.AtomEntryElementName)); } } } } } return linkContent; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ScrollViewer.cs
- Event.cs
- UnsafeNativeMethods.cs
- NamespaceInfo.cs
- ImageListStreamer.cs
- LinqDataSourceHelper.cs
- SubstitutionDesigner.cs
- BamlLocalizableResourceKey.cs
- Rect.cs
- LogEntryDeserializer.cs
- SiteMapNodeItemEventArgs.cs
- MemberDomainMap.cs
- FacetDescriptionElement.cs
- CompositeScriptReference.cs
- Int32AnimationUsingKeyFrames.cs
- DesignTimeVisibleAttribute.cs
- CodeFieldReferenceExpression.cs
- ErrorRuntimeConfig.cs
- ModulesEntry.cs
- EmbeddedMailObject.cs
- BitmapMetadata.cs
- unsafenativemethodsother.cs
- TypeValidationEventArgs.cs
- RoleManagerEventArgs.cs
- SerializationBinder.cs
- TextCharacters.cs
- MetadataResolver.cs
- SeekStoryboard.cs
- SafeArrayRankMismatchException.cs
- BaseValidator.cs
- ComplexLine.cs
- Types.cs
- InputMethodStateTypeInfo.cs
- ResourceAttributes.cs
- ping.cs
- EntityProxyFactory.cs
- GetUserPreferenceRequest.cs
- XmlSchemaProviderAttribute.cs
- FormConverter.cs
- WindowVisualStateTracker.cs
- Base64Decoder.cs
- XamlReader.cs
- HelloMessageCD1.cs
- Package.cs
- MessageHeaderException.cs
- Cast.cs
- ConfigXmlElement.cs
- ToolStrip.cs
- LookupBindingPropertiesAttribute.cs
- EqualityComparer.cs
- SqlAliaser.cs
- FilteredAttributeCollection.cs
- BamlLocalizer.cs
- PolicyValidationException.cs
- cache.cs
- Transform3DGroup.cs
- TimeManager.cs
- ListComponentEditor.cs
- FrameworkElement.cs
- _BasicClient.cs
- ImportCatalogPart.cs
- MergeFailedEvent.cs
- XPathDocumentNavigator.cs
- NullRuntimeConfig.cs
- MimeReturn.cs
- ConcurrencyMode.cs
- FixedPageStructure.cs
- Graphics.cs
- ParserStreamGeometryContext.cs
- Profiler.cs
- HostAdapter.cs
- IfJoinedCondition.cs
- XmlEnumAttribute.cs
- StrongTypingException.cs
- SvcMapFileLoader.cs
- DeclarativeCatalogPart.cs
- Positioning.cs
- Propagator.JoinPropagator.JoinPredicateVisitor.cs
- HttpWebRequest.cs
- XmlChildNodes.cs
- CqlIdentifiers.cs
- SQLGuid.cs
- DataGridCell.cs
- FontFamily.cs
- AuthenticateEventArgs.cs
- DBProviderConfigurationHandler.cs
- BaseDataListDesigner.cs
- ExpandCollapseProviderWrapper.cs
- UMPAttributes.cs
- DataServiceRequest.cs
- SqlCrossApplyToCrossJoin.cs
- TCPClient.cs
- Peer.cs
- TemplateBindingExpression.cs
- AssemblyHash.cs
- TableNameAttribute.cs
- DataServiceQueryException.cs
- Timer.cs
- SafeCertificateContext.cs
- UntrustedRecipientException.cs