Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / JsonSerializer.cs / 1 / JsonSerializer.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a serializer for the Json format. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Serializers { using System; using System.Collections; using System.Data.Services.Providers; using System.Diagnostics; using System.IO; using System.Text; ////// Provides support for serializing responses in JSON format. /// ///For more information, see http://www.json.org/. [DebuggerDisplay("Json={absoluteServiceUri}")] internal sealed class JsonSerializer : Serializer { ///JsonWriter to write out strings in Json format. private readonly JsonWriter writer; ////// Initializes a new /// Description for the requested results. /// Stream to which output should be sent. /// Absolute URI to the service entry point. /// Service with configuration and provider from which metadata should be gathered. /// Text encoding for the response. /// HTTP ETag header value. internal JsonSerializer( RequestDescription requestDescription, Stream output, Uri absoluteServiceUri, IDataService service, Encoding encoding, string httpETagHeaderValue) : base(requestDescription, absoluteServiceUri, service, httpETagHeaderValue) { Debug.Assert(output != null, "output != null"); Debug.Assert(encoding != null, "encoding != null"); StreamWriter writer = new StreamWriter(output, encoding); this.writer = new JsonWriter(writer); } ///, ready to write out a description. /// Serializes exception information. /// Description of exception to serialize. public override void WriteException(HandleExceptionArgs args) { ErrorHandler.SerializeJsonError(args, this.writer); } ///Flushes the writer to the underlying stream. protected override void Flush() { this.writer.Flush(); } ///Writes a single top-level element. /// Expanded properties for the result. /// Element to write, possibly null. protected override void WriteTopLevelElement(IExpandedResult expanded, object element) { Debug.Assert(this.RequestDescription.IsSingleResult, "this.RequestDescription.SingleResult"); this.PushSegmentForRoot(); this.writer.StartWrapper(); this.WriteElementWithName(expanded, element, this.RequestDescription.ContainerName, this.RequestDescription.ResultUri, true /*topLevel*/); this.writer.EndWrapper(); this.PopSegmentName(); } ///Writes multiple top-level elements, possibly none. /// Expanded properties for the result. /// Enumerator for elements to write. /// Whetherwas succesfully advanced to the first element. protected override void WriteTopLevelElements(IExpandedResult expanded, IEnumerator elements, bool hasMoved) { Debug.Assert(elements != null, "elements != null"); Debug.Assert(!this.RequestDescription.IsSingleResult, "!this.RequestDescription.SingleResult"); this.PushSegmentForRoot(); Uri parentUri = this.RequestDescription.ResultUri; this.writer.StartWrapper(); this.writer.StartArrayScope(); while (hasMoved) { object o = elements.Current; if (o != null) { this.WriteElementWithName(expanded, o, null, parentUri, false /*topLevel*/); } hasMoved = elements.MoveNext(); } this.writer.EndScope(); this.writer.EndWrapper(); this.PopSegmentName(); } /// Writes out the uri for the given element. /// element whose uri needs to be written out. ///This method accounts for a written entity on the current segment. protected override void WriteLink(object element) { Debug.Assert(element != null, "element != null"); ResourceContainer container = this.GetContainerForCurrent(element); Uri uri = Serializer.GetUri(element, this.Provider, container, this.AbsoluteServiceUri); this.writer.StartWrapper(); this.WriteLinkObject(uri); this.writer.EndWrapper(); } ////// Write out the uri for the given elements. /// /// elements whose uri need to be writtne out /// the current state of the enumerator. ///This method accounts for each link as a written entity on the current segment. protected override void WriteLinkCollection(IEnumerator elements, bool hasMoved) { this.writer.StartWrapper(); this.writer.StartArrayScope(); while (hasMoved) { object o = elements.Current; if (o != null) { ResourceContainer container = this.GetContainerForCurrent(o); Uri uri = Serializer.GetUri(o, this.Provider, container, this.AbsoluteServiceUri); this.WriteLinkObject(uri); } hasMoved = elements.MoveNext(); } this.writer.EndScope(); this.writer.EndWrapper(); } ///Gets the tag name to be used when writing the specified type. /// Provider with metadata to be used for lookups. /// Type of resource to be written. ///The tag name to be used when writing he specified type. private static string GetTagNameForType(IDataServiceProvider provider, ResourceType resourceType) { Debug.Assert(provider != null, "provider != null"); Debug.Assert(resourceType != null, "resourceType != null"); ResourceType elementType = provider.GetRootType(resourceType); string tagName = elementType.Name; if (!System.Xml.XmlReader.IsName(tagName)) { tagName = System.Xml.XmlConvert.EncodeName(elementType.Name); } return tagName; } ///Write the link uri in the payload. /// uri which needs to be written. ///This method accounts for a written entity on the current segment. private void WriteLinkObject(Uri uri) { this.IncrementSegmentResultCount(); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.UriElementName); this.writer.WriteValue(uri.AbsoluteUri); this.writer.EndScope(); } ////// Attempts to convert the specified primitive value to a serializable string. /// /// Non-null value to convert. private void WritePrimitiveValue(object value) { Debug.Assert(value != null, "value != null"); Type valueType = value.GetType(); if (typeof(String) == valueType) { this.writer.WriteValue((string)value); } else if (typeof(System.Xml.Linq.XElement) == valueType) { this.writer.WriteValue(((System.Xml.Linq.XElement)value).ToString(System.Xml.Linq.SaveOptions.None)); } else if (typeof(SByte) == valueType) { this.writer.WriteValue((SByte)value); } else if (typeof(Boolean) == value.GetType()) { this.writer.WriteValue((bool)value); } else if (typeof(Byte) == value.GetType()) { this.writer.WriteValue((byte)value); } else if (typeof(DateTime) == value.GetType()) { this.writer.WriteValue((DateTime)value); } else if (typeof(Decimal) == value.GetType()) { this.writer.WriteValue((Decimal)value); } else if (typeof(Double) == value.GetType()) { this.writer.WriteValue((Double)value); } else if (typeof(Guid) == value.GetType()) { this.writer.WriteValue((Guid)value); } else if (typeof(Int16) == value.GetType()) { this.writer.WriteValue((Int16)value); } else if (typeof(Int32) == value.GetType()) { this.writer.WriteValue((Int32)value); } else if (typeof(Int64) == value.GetType()) { this.writer.WriteValue((Int64)value); } else if (typeof(Single) == value.GetType()) { this.writer.WriteValue((Single)value); } else if (typeof(byte[]) == value.GetType()) { byte[] byteArray = (byte[])value; string result = Convert.ToBase64String(byteArray, Base64FormattingOptions.None); this.writer.WriteValue(result); } else { Debug.Assert(typeof(System.Data.Linq.Binary) == value.GetType(), "typeof(Binary) == value.GetType() (" + value.GetType() + ")"); this.WritePrimitiveValue(((System.Data.Linq.Binary)value).ToArray()); } } ///Writes the ID and uri path information for the specified resource. /// Resource for which URI information should be written. /// type of the resource /// uri of the resource for which the metadata is getting written ///The tag name for the resource that was written. private string WriteMetadataObject(object resource, ResourceType resourceType, Uri uriPath) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(uriPath != null || resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType, "uri can be null for complex types"); this.writer.WriteName(XmlConstants.JsonMetadataString); this.writer.StartObjectScope(); // Write uri value only for entity types if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) { this.writer.WriteName(XmlConstants.JsonUriString); this.writer.WriteValue(uriPath.AbsoluteUri); // Write the etag property, if the type has etag properties string etag = this.GetETagValue(resource); if (etag != null) { this.writer.WriteName(XmlConstants.JsonETagString); this.writer.WriteValue(etag); } } this.writer.WriteName(XmlConstants.JsonTypeString); // For generic types, we need to remove the assembly qualified names for the argument types this.writer.WriteValue(resourceType.FullName); this.writer.EndScope(); return GetTagNameForType(this.Provider, resourceType); } ///Writes an element with an optional specified name. /// Expanded properties for the result. /// Element to write, possibly null. /// Name of element to write, possibly null. /// URI of element to write. /// whether the element is a top level element or not. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", MessageId = "elementName", Justification = "Pending review")] private void WriteElementWithName(IExpandedResult expanded, object element, string elementName, Uri elementUri, bool topLevel) { Debug.Assert(elementName == null || elementName.Length > 0, "elementName == null || elementName.Length > 0"); Debug.Assert(elementUri != null, "elementUri != null"); if (element == null) { if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); this.WriteNullValue(); this.writer.EndScope(); } else { this.WriteNullValue(); } } else { IEnumerable enumerableElement; if (WebUtil.IsElementIEnumerable(element, out enumerableElement)) { Debug.Assert(elementName != null, "elementName != null - only collection properties are handled here"); this.writer.StartArrayScope(); IEnumerator enumerator = enumerableElement.GetEnumerator(); try { IExpandedResult expandedEnumerator = enumerator as IExpandedResult; while (enumerator.MoveNext()) { object elementInCollection = enumerator.Current; if (elementInCollection != null) { if (elementInCollection is IExpandedResult) { expandedEnumerator = (IExpandedResult)elementInCollection; elementInCollection = expandedEnumerator.ExpandedElement; } this.WriteElementWithName(expandedEnumerator, elementInCollection, null, elementUri, false /*topLevel*/); } } } finally { WebUtil.Dispose(enumerator); } this.writer.EndScope(); return; } Type elementType = element.GetType(); ResourceType resourceType = this.Provider.GetResourceType(elementType); if (resourceType == null) { // Skip this element. return; } switch (resourceType.ResourceTypeKind) { case ResourceTypeKind.ComplexType: if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); } // Non-value complex types may form a cycle. // PERF: we can keep a single element around and save the HashSet initialization // until we find a second complex type - this saves the allocation on trees // with shallow (single-level) complex types. if (this.AddToComplexTypeCollection(element)) { this.WriteComplexTypeProperties(element, resourceType, elementUri); this.RemoveFromComplexTypeCollection(element); } else { throw new InvalidOperationException(Strings.DataServiceException_GeneralError); } if (topLevel) { this.writer.EndScope(); } break; case ResourceTypeKind.EntityType: this.IncrementSegmentResultCount(); this.writer.StartObjectScope(); Uri entityUri = Serializer.GetUri(element, this.Provider, this.GetContainerForCurrent(element), this.AbsoluteServiceUri); this.WriteMetadataObject(element, resourceType, entityUri); this.WriteResourceProperties(expanded, element, resourceType, entityUri); this.writer.EndScope(); break; default: Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.Primitive, "resourceType.ResourceTypeKind == ResourceTypeKind.Primitive"); if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); this.WritePrimitiveValue(element); this.writer.EndScope(); } else { this.WritePrimitiveValue(element); } break; } } } ///Writes all the properties of the specified resource. /// Expanded properties for the result. /// Resource with properties to write out. /// Type for the specified resource (saves the lookup in this method). /// uri of the resource whose properties are getting written private void WriteResourceProperties(IExpandedResult expanded, object resource, ResourceType resourceType, Uri uri) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "resource must be entity type"); Debug.Assert(uri != null, "uri != null"); this.WriteObjectProperties(expanded, resource, resourceType, uri, true); } ///Writes all the properties of the specified complex type. /// Object of a complex type with properties to be written out. /// resource type representing the current object /// uri of the complex type whose properties needs to be written private void WriteComplexTypeProperties(object complexObject, ResourceType resourceType, Uri parentUri) { Debug.Assert(complexObject != null, "complexObject != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType, "resource must be complex type"); Debug.Assert(resourceType.Type.IsAssignableFrom(complexObject.GetType()), "resourceType.Type.IsAssignableFrom(complexObject.GetType())"); this.writer.StartObjectScope(); this.WriteMetadataObject(complexObject, resourceType, null); this.WriteObjectProperties(null, complexObject, resourceType, parentUri, false); this.writer.EndScope(); } ///Writes a JSON _deferred element. /// uri of the element which is getting deferred private void WriteDeferredContentElement(Uri uri) { Debug.Assert(uri != null, "uri != null"); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.JsonDeferredString); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.JsonUriString); this.writer.WriteValue(uri.AbsoluteUri); this.writer.EndScope(); this.writer.EndScope(); } ///Writes an attribute to indicate that there is no value. private void WriteNullValue() { this.writer.WriteValue((string)null); } ///Writes all the properties of the specified resource or complex object. /// Expanded properties for the result. /// Resource or complex object with properties to write out. /// Resource Type representing the given object instance. /// uri of the object whose properties are getting written /// true if the specified object is a resource; false otherwise. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", MessageId = "objectIsResource", Justification = "Pending review")] private void WriteObjectProperties(IExpandedResult expanded, object customObject, ResourceType resourceType, Uri parentUri, bool objectIsResource) { Debug.Assert(customObject != null, "customObject != null"); Debug.Assert(resourceType != null, "customObjectType != null"); Debug.Assert(resourceType.Type == customObject.GetType(), "resourceType.Type == customObject.GetType()"); Debug.Assert(parentUri != null, "parentUri != null"); Debug.Assert(resourceType.ResourceTypeKind != ResourceTypeKind.Primitive, "resourceType.ResourceTypeKind == ResourceTypeKind.Primitive"); // We should throw while if there are navigation properties in the derived entity type if (this.CurrentContainer != null && this.CurrentContainer.IsEntityDisallowed(resourceType)) { throw new InvalidOperationException(Strings.BaseServiceProvider_NavigationPropertiesOnDerivedEntityTypesNotSupported(resourceType.FullName, this.CurrentContainer.Name)); } foreach (ResourceProperty property in resourceType.Properties) { Debug.Assert( objectIsResource || !property.IsOfKind(ResourcePropertyKind.Key), "objectIsResource || property.Kind != ResourcePropertyKind.KeyPrimitive - complex types shouldn't have key properties"); string propertyName = property.Name; this.writer.WriteName(propertyName); // For any navigation property, we just stick the deferred element with the uri // This uri is different from the canonical uri: we just append the property name // to the parent uri. We don't want to analyze the nav property value in either case bool mayDefer = property.TypeKind == ResourceTypeKind.EntityType; if (mayDefer && !this.ShouldExpandSegment(propertyName)) { this.WriteDeferredContentElement(Serializer.AppendEntryToUri(parentUri, propertyName)); } else { object propertyValue; IExpandedResult expandedValue = null; if (mayDefer) { propertyValue = GetExpandedProperty(expanded, customObject, property); expandedValue = propertyValue as IExpandedResult; if (expandedValue != null) { propertyValue = expandedValue.ExpandedElement; } } else { propertyValue = GetExpandedProperty(null, customObject, property); } this.PushSegmentForProperty(property); this.WriteElementWithName(expandedValue, propertyValue, propertyName, Serializer.AppendEntryToUri(parentUri, propertyName), false /*topLevel*/); this.PopSegmentName(); } } #if ASTORIA_OPEN_OBJECT if (resourceType.IsOpenType) { foreach (var pair in OpenTypeAttribute.EnumerateOpenProperties(customObject)) { string propertyName = pair.Key; object propertyValue = pair.Value; IExpandedResult expandedValue = propertyValue as IExpandedResult; if (expandedValue != null) { propertyValue = expandedValue.ExpandedElement; } // Ignore open properties with null values if (propertyValue == null || propertyValue == DBNull.Value) { continue; } // We need to ensure that strings and other primitive types which implement IEnumerable // are not considered as containing elements. Type propertyValueType = propertyValue.GetType(); Type propertyElementType = WebUtil.IsPrimitiveType(propertyValueType) ? null : BaseServiceProvider.GetIEnumerableElement(propertyValueType); propertyElementType = propertyElementType ?? propertyValueType; ResourceType propertyResourceType = this.Provider.GetResourceType(propertyElementType); if (propertyResourceType == null) { // Black-listed types are not supported. continue; } ResourceTypeKind kind = propertyResourceType.ResourceTypeKind; if (propertyElementType != propertyValueType && kind != ResourceTypeKind.EntityType) { // Only enumerations of entities are supported. continue; } this.writer.WriteName(propertyName); if (kind != ResourceTypeKind.EntityType || this.ShouldExpandSegment(propertyName)) { this.PushSegmentForOpenProperty(propertyName, propertyResourceType); this.WriteElementWithName(expandedValue, propertyValue, propertyName, Serializer.AppendEntryToUri(parentUri, propertyName), false /*topLevel*/); this.PopSegmentName(); } else { // For collection properties, we need to add () at the end to make it a valid uri string segmentIdentifier = propertyName; if (propertyElementType != propertyValueType) { segmentIdentifier += "()"; } this.WriteDeferredContentElement(Serializer.AppendEntryToUri(parentUri, segmentIdentifier)); } } } #endif } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a serializer for the Json format. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Serializers { using System; using System.Collections; using System.Data.Services.Providers; using System.Diagnostics; using System.IO; using System.Text; ////// Provides support for serializing responses in JSON format. /// ///For more information, see http://www.json.org/. [DebuggerDisplay("Json={absoluteServiceUri}")] internal sealed class JsonSerializer : Serializer { ///JsonWriter to write out strings in Json format. private readonly JsonWriter writer; ////// Initializes a new /// Description for the requested results. /// Stream to which output should be sent. /// Absolute URI to the service entry point. /// Service with configuration and provider from which metadata should be gathered. /// Text encoding for the response. /// HTTP ETag header value. internal JsonSerializer( RequestDescription requestDescription, Stream output, Uri absoluteServiceUri, IDataService service, Encoding encoding, string httpETagHeaderValue) : base(requestDescription, absoluteServiceUri, service, httpETagHeaderValue) { Debug.Assert(output != null, "output != null"); Debug.Assert(encoding != null, "encoding != null"); StreamWriter writer = new StreamWriter(output, encoding); this.writer = new JsonWriter(writer); } ///, ready to write out a description. /// Serializes exception information. /// Description of exception to serialize. public override void WriteException(HandleExceptionArgs args) { ErrorHandler.SerializeJsonError(args, this.writer); } ///Flushes the writer to the underlying stream. protected override void Flush() { this.writer.Flush(); } ///Writes a single top-level element. /// Expanded properties for the result. /// Element to write, possibly null. protected override void WriteTopLevelElement(IExpandedResult expanded, object element) { Debug.Assert(this.RequestDescription.IsSingleResult, "this.RequestDescription.SingleResult"); this.PushSegmentForRoot(); this.writer.StartWrapper(); this.WriteElementWithName(expanded, element, this.RequestDescription.ContainerName, this.RequestDescription.ResultUri, true /*topLevel*/); this.writer.EndWrapper(); this.PopSegmentName(); } ///Writes multiple top-level elements, possibly none. /// Expanded properties for the result. /// Enumerator for elements to write. /// Whetherwas succesfully advanced to the first element. protected override void WriteTopLevelElements(IExpandedResult expanded, IEnumerator elements, bool hasMoved) { Debug.Assert(elements != null, "elements != null"); Debug.Assert(!this.RequestDescription.IsSingleResult, "!this.RequestDescription.SingleResult"); this.PushSegmentForRoot(); Uri parentUri = this.RequestDescription.ResultUri; this.writer.StartWrapper(); this.writer.StartArrayScope(); while (hasMoved) { object o = elements.Current; if (o != null) { this.WriteElementWithName(expanded, o, null, parentUri, false /*topLevel*/); } hasMoved = elements.MoveNext(); } this.writer.EndScope(); this.writer.EndWrapper(); this.PopSegmentName(); } /// Writes out the uri for the given element. /// element whose uri needs to be written out. ///This method accounts for a written entity on the current segment. protected override void WriteLink(object element) { Debug.Assert(element != null, "element != null"); ResourceContainer container = this.GetContainerForCurrent(element); Uri uri = Serializer.GetUri(element, this.Provider, container, this.AbsoluteServiceUri); this.writer.StartWrapper(); this.WriteLinkObject(uri); this.writer.EndWrapper(); } ////// Write out the uri for the given elements. /// /// elements whose uri need to be writtne out /// the current state of the enumerator. ///This method accounts for each link as a written entity on the current segment. protected override void WriteLinkCollection(IEnumerator elements, bool hasMoved) { this.writer.StartWrapper(); this.writer.StartArrayScope(); while (hasMoved) { object o = elements.Current; if (o != null) { ResourceContainer container = this.GetContainerForCurrent(o); Uri uri = Serializer.GetUri(o, this.Provider, container, this.AbsoluteServiceUri); this.WriteLinkObject(uri); } hasMoved = elements.MoveNext(); } this.writer.EndScope(); this.writer.EndWrapper(); } ///Gets the tag name to be used when writing the specified type. /// Provider with metadata to be used for lookups. /// Type of resource to be written. ///The tag name to be used when writing he specified type. private static string GetTagNameForType(IDataServiceProvider provider, ResourceType resourceType) { Debug.Assert(provider != null, "provider != null"); Debug.Assert(resourceType != null, "resourceType != null"); ResourceType elementType = provider.GetRootType(resourceType); string tagName = elementType.Name; if (!System.Xml.XmlReader.IsName(tagName)) { tagName = System.Xml.XmlConvert.EncodeName(elementType.Name); } return tagName; } ///Write the link uri in the payload. /// uri which needs to be written. ///This method accounts for a written entity on the current segment. private void WriteLinkObject(Uri uri) { this.IncrementSegmentResultCount(); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.UriElementName); this.writer.WriteValue(uri.AbsoluteUri); this.writer.EndScope(); } ////// Attempts to convert the specified primitive value to a serializable string. /// /// Non-null value to convert. private void WritePrimitiveValue(object value) { Debug.Assert(value != null, "value != null"); Type valueType = value.GetType(); if (typeof(String) == valueType) { this.writer.WriteValue((string)value); } else if (typeof(System.Xml.Linq.XElement) == valueType) { this.writer.WriteValue(((System.Xml.Linq.XElement)value).ToString(System.Xml.Linq.SaveOptions.None)); } else if (typeof(SByte) == valueType) { this.writer.WriteValue((SByte)value); } else if (typeof(Boolean) == value.GetType()) { this.writer.WriteValue((bool)value); } else if (typeof(Byte) == value.GetType()) { this.writer.WriteValue((byte)value); } else if (typeof(DateTime) == value.GetType()) { this.writer.WriteValue((DateTime)value); } else if (typeof(Decimal) == value.GetType()) { this.writer.WriteValue((Decimal)value); } else if (typeof(Double) == value.GetType()) { this.writer.WriteValue((Double)value); } else if (typeof(Guid) == value.GetType()) { this.writer.WriteValue((Guid)value); } else if (typeof(Int16) == value.GetType()) { this.writer.WriteValue((Int16)value); } else if (typeof(Int32) == value.GetType()) { this.writer.WriteValue((Int32)value); } else if (typeof(Int64) == value.GetType()) { this.writer.WriteValue((Int64)value); } else if (typeof(Single) == value.GetType()) { this.writer.WriteValue((Single)value); } else if (typeof(byte[]) == value.GetType()) { byte[] byteArray = (byte[])value; string result = Convert.ToBase64String(byteArray, Base64FormattingOptions.None); this.writer.WriteValue(result); } else { Debug.Assert(typeof(System.Data.Linq.Binary) == value.GetType(), "typeof(Binary) == value.GetType() (" + value.GetType() + ")"); this.WritePrimitiveValue(((System.Data.Linq.Binary)value).ToArray()); } } ///Writes the ID and uri path information for the specified resource. /// Resource for which URI information should be written. /// type of the resource /// uri of the resource for which the metadata is getting written ///The tag name for the resource that was written. private string WriteMetadataObject(object resource, ResourceType resourceType, Uri uriPath) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(uriPath != null || resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType, "uri can be null for complex types"); this.writer.WriteName(XmlConstants.JsonMetadataString); this.writer.StartObjectScope(); // Write uri value only for entity types if (resourceType.ResourceTypeKind == ResourceTypeKind.EntityType) { this.writer.WriteName(XmlConstants.JsonUriString); this.writer.WriteValue(uriPath.AbsoluteUri); // Write the etag property, if the type has etag properties string etag = this.GetETagValue(resource); if (etag != null) { this.writer.WriteName(XmlConstants.JsonETagString); this.writer.WriteValue(etag); } } this.writer.WriteName(XmlConstants.JsonTypeString); // For generic types, we need to remove the assembly qualified names for the argument types this.writer.WriteValue(resourceType.FullName); this.writer.EndScope(); return GetTagNameForType(this.Provider, resourceType); } ///Writes an element with an optional specified name. /// Expanded properties for the result. /// Element to write, possibly null. /// Name of element to write, possibly null. /// URI of element to write. /// whether the element is a top level element or not. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", MessageId = "elementName", Justification = "Pending review")] private void WriteElementWithName(IExpandedResult expanded, object element, string elementName, Uri elementUri, bool topLevel) { Debug.Assert(elementName == null || elementName.Length > 0, "elementName == null || elementName.Length > 0"); Debug.Assert(elementUri != null, "elementUri != null"); if (element == null) { if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); this.WriteNullValue(); this.writer.EndScope(); } else { this.WriteNullValue(); } } else { IEnumerable enumerableElement; if (WebUtil.IsElementIEnumerable(element, out enumerableElement)) { Debug.Assert(elementName != null, "elementName != null - only collection properties are handled here"); this.writer.StartArrayScope(); IEnumerator enumerator = enumerableElement.GetEnumerator(); try { IExpandedResult expandedEnumerator = enumerator as IExpandedResult; while (enumerator.MoveNext()) { object elementInCollection = enumerator.Current; if (elementInCollection != null) { if (elementInCollection is IExpandedResult) { expandedEnumerator = (IExpandedResult)elementInCollection; elementInCollection = expandedEnumerator.ExpandedElement; } this.WriteElementWithName(expandedEnumerator, elementInCollection, null, elementUri, false /*topLevel*/); } } } finally { WebUtil.Dispose(enumerator); } this.writer.EndScope(); return; } Type elementType = element.GetType(); ResourceType resourceType = this.Provider.GetResourceType(elementType); if (resourceType == null) { // Skip this element. return; } switch (resourceType.ResourceTypeKind) { case ResourceTypeKind.ComplexType: if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); } // Non-value complex types may form a cycle. // PERF: we can keep a single element around and save the HashSet initialization // until we find a second complex type - this saves the allocation on trees // with shallow (single-level) complex types. if (this.AddToComplexTypeCollection(element)) { this.WriteComplexTypeProperties(element, resourceType, elementUri); this.RemoveFromComplexTypeCollection(element); } else { throw new InvalidOperationException(Strings.DataServiceException_GeneralError); } if (topLevel) { this.writer.EndScope(); } break; case ResourceTypeKind.EntityType: this.IncrementSegmentResultCount(); this.writer.StartObjectScope(); Uri entityUri = Serializer.GetUri(element, this.Provider, this.GetContainerForCurrent(element), this.AbsoluteServiceUri); this.WriteMetadataObject(element, resourceType, entityUri); this.WriteResourceProperties(expanded, element, resourceType, entityUri); this.writer.EndScope(); break; default: Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.Primitive, "resourceType.ResourceTypeKind == ResourceTypeKind.Primitive"); if (topLevel) { this.writer.StartObjectScope(); this.writer.WriteName(elementName); this.WritePrimitiveValue(element); this.writer.EndScope(); } else { this.WritePrimitiveValue(element); } break; } } } ///Writes all the properties of the specified resource. /// Expanded properties for the result. /// Resource with properties to write out. /// Type for the specified resource (saves the lookup in this method). /// uri of the resource whose properties are getting written private void WriteResourceProperties(IExpandedResult expanded, object resource, ResourceType resourceType, Uri uri) { Debug.Assert(resource != null, "resource != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "resource must be entity type"); Debug.Assert(uri != null, "uri != null"); this.WriteObjectProperties(expanded, resource, resourceType, uri, true); } ///Writes all the properties of the specified complex type. /// Object of a complex type with properties to be written out. /// resource type representing the current object /// uri of the complex type whose properties needs to be written private void WriteComplexTypeProperties(object complexObject, ResourceType resourceType, Uri parentUri) { Debug.Assert(complexObject != null, "complexObject != null"); Debug.Assert(resourceType != null, "resourceType != null"); Debug.Assert(resourceType.ResourceTypeKind == ResourceTypeKind.ComplexType, "resource must be complex type"); Debug.Assert(resourceType.Type.IsAssignableFrom(complexObject.GetType()), "resourceType.Type.IsAssignableFrom(complexObject.GetType())"); this.writer.StartObjectScope(); this.WriteMetadataObject(complexObject, resourceType, null); this.WriteObjectProperties(null, complexObject, resourceType, parentUri, false); this.writer.EndScope(); } ///Writes a JSON _deferred element. /// uri of the element which is getting deferred private void WriteDeferredContentElement(Uri uri) { Debug.Assert(uri != null, "uri != null"); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.JsonDeferredString); this.writer.StartObjectScope(); this.writer.WriteName(XmlConstants.JsonUriString); this.writer.WriteValue(uri.AbsoluteUri); this.writer.EndScope(); this.writer.EndScope(); } ///Writes an attribute to indicate that there is no value. private void WriteNullValue() { this.writer.WriteValue((string)null); } ///Writes all the properties of the specified resource or complex object. /// Expanded properties for the result. /// Resource or complex object with properties to write out. /// Resource Type representing the given object instance. /// uri of the object whose properties are getting written /// true if the specified object is a resource; false otherwise. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", MessageId = "objectIsResource", Justification = "Pending review")] private void WriteObjectProperties(IExpandedResult expanded, object customObject, ResourceType resourceType, Uri parentUri, bool objectIsResource) { Debug.Assert(customObject != null, "customObject != null"); Debug.Assert(resourceType != null, "customObjectType != null"); Debug.Assert(resourceType.Type == customObject.GetType(), "resourceType.Type == customObject.GetType()"); Debug.Assert(parentUri != null, "parentUri != null"); Debug.Assert(resourceType.ResourceTypeKind != ResourceTypeKind.Primitive, "resourceType.ResourceTypeKind == ResourceTypeKind.Primitive"); // We should throw while if there are navigation properties in the derived entity type if (this.CurrentContainer != null && this.CurrentContainer.IsEntityDisallowed(resourceType)) { throw new InvalidOperationException(Strings.BaseServiceProvider_NavigationPropertiesOnDerivedEntityTypesNotSupported(resourceType.FullName, this.CurrentContainer.Name)); } foreach (ResourceProperty property in resourceType.Properties) { Debug.Assert( objectIsResource || !property.IsOfKind(ResourcePropertyKind.Key), "objectIsResource || property.Kind != ResourcePropertyKind.KeyPrimitive - complex types shouldn't have key properties"); string propertyName = property.Name; this.writer.WriteName(propertyName); // For any navigation property, we just stick the deferred element with the uri // This uri is different from the canonical uri: we just append the property name // to the parent uri. We don't want to analyze the nav property value in either case bool mayDefer = property.TypeKind == ResourceTypeKind.EntityType; if (mayDefer && !this.ShouldExpandSegment(propertyName)) { this.WriteDeferredContentElement(Serializer.AppendEntryToUri(parentUri, propertyName)); } else { object propertyValue; IExpandedResult expandedValue = null; if (mayDefer) { propertyValue = GetExpandedProperty(expanded, customObject, property); expandedValue = propertyValue as IExpandedResult; if (expandedValue != null) { propertyValue = expandedValue.ExpandedElement; } } else { propertyValue = GetExpandedProperty(null, customObject, property); } this.PushSegmentForProperty(property); this.WriteElementWithName(expandedValue, propertyValue, propertyName, Serializer.AppendEntryToUri(parentUri, propertyName), false /*topLevel*/); this.PopSegmentName(); } } #if ASTORIA_OPEN_OBJECT if (resourceType.IsOpenType) { foreach (var pair in OpenTypeAttribute.EnumerateOpenProperties(customObject)) { string propertyName = pair.Key; object propertyValue = pair.Value; IExpandedResult expandedValue = propertyValue as IExpandedResult; if (expandedValue != null) { propertyValue = expandedValue.ExpandedElement; } // Ignore open properties with null values if (propertyValue == null || propertyValue == DBNull.Value) { continue; } // We need to ensure that strings and other primitive types which implement IEnumerable // are not considered as containing elements. Type propertyValueType = propertyValue.GetType(); Type propertyElementType = WebUtil.IsPrimitiveType(propertyValueType) ? null : BaseServiceProvider.GetIEnumerableElement(propertyValueType); propertyElementType = propertyElementType ?? propertyValueType; ResourceType propertyResourceType = this.Provider.GetResourceType(propertyElementType); if (propertyResourceType == null) { // Black-listed types are not supported. continue; } ResourceTypeKind kind = propertyResourceType.ResourceTypeKind; if (propertyElementType != propertyValueType && kind != ResourceTypeKind.EntityType) { // Only enumerations of entities are supported. continue; } this.writer.WriteName(propertyName); if (kind != ResourceTypeKind.EntityType || this.ShouldExpandSegment(propertyName)) { this.PushSegmentForOpenProperty(propertyName, propertyResourceType); this.WriteElementWithName(expandedValue, propertyValue, propertyName, Serializer.AppendEntryToUri(parentUri, propertyName), false /*topLevel*/); this.PopSegmentName(); } else { // For collection properties, we need to add () at the end to make it a valid uri string segmentIdentifier = propertyName; if (propertyElementType != propertyValueType) { segmentIdentifier += "()"; } this.WriteDeferredContentElement(Serializer.AppendEntryToUri(parentUri, segmentIdentifier)); } } } #endif } } } // 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
- Matrix.cs
- OptionUsage.cs
- IpcChannel.cs
- DirectionalLight.cs
- OpCodes.cs
- MarshalDirectiveException.cs
- SatelliteContractVersionAttribute.cs
- NotifyInputEventArgs.cs
- TagMapCollection.cs
- SpecularMaterial.cs
- CacheSection.cs
- IgnorePropertiesAttribute.cs
- WebDescriptionAttribute.cs
- EntryPointNotFoundException.cs
- DispatchWrapper.cs
- DataContract.cs
- CqlGenerator.cs
- ExtendedProperty.cs
- OleDbRowUpdatedEvent.cs
- Parameter.cs
- PolyQuadraticBezierSegment.cs
- Transactions.cs
- AsymmetricKeyExchangeFormatter.cs
- DeferredBinaryDeserializerExtension.cs
- ConditionValidator.cs
- XsltContext.cs
- ContentControl.cs
- SmiMetaDataProperty.cs
- AbandonedMutexException.cs
- TemplateBindingExtension.cs
- RelOps.cs
- BaseConfigurationRecord.cs
- StyleXamlTreeBuilder.cs
- UnmanagedMarshal.cs
- TableCell.cs
- EdmItemCollection.cs
- DynamicField.cs
- FieldNameLookup.cs
- AppSettingsSection.cs
- HttpProtocolImporter.cs
- GlyphRun.cs
- SamlSubjectStatement.cs
- XmlElement.cs
- Converter.cs
- ComEventsInfo.cs
- AncillaryOps.cs
- userdatakeys.cs
- XmlImplementation.cs
- LiteralControl.cs
- CaseDesigner.xaml.cs
- DoubleAnimationClockResource.cs
- CompilationUtil.cs
- PrinterResolution.cs
- ProcessHostFactoryHelper.cs
- ClosureBinding.cs
- Attributes.cs
- StringCollectionEditor.cs
- SubMenuStyle.cs
- StyleHelper.cs
- SafeSecurityHelper.cs
- AuthenticateEventArgs.cs
- MarkerProperties.cs
- ConstraintStruct.cs
- ListControl.cs
- PtsContext.cs
- XmlAttribute.cs
- ScopelessEnumAttribute.cs
- HtmlMeta.cs
- XhtmlBasicControlAdapter.cs
- DesignTimeHTMLTextWriter.cs
- PointIndependentAnimationStorage.cs
- ParameterElement.cs
- BinaryFormatterWriter.cs
- DataGridViewBand.cs
- streamingZipPartStream.cs
- BitmapEffectGroup.cs
- InfoCardTrace.cs
- EnumValAlphaComparer.cs
- Pair.cs
- ConfigurationConverterBase.cs
- HealthMonitoringSectionHelper.cs
- DataServiceQueryProvider.cs
- WindowsServiceCredential.cs
- CustomCategoryAttribute.cs
- baseshape.cs
- StrokeFIndices.cs
- GetTokenRequest.cs
- AffineTransform3D.cs
- LabelLiteral.cs
- WorkflowControlClient.cs
- Image.cs
- HtmlHead.cs
- LicenseProviderAttribute.cs
- StructuredType.cs
- SelectionProcessor.cs
- DefaultExpression.cs
- BlobPersonalizationState.cs
- RegexBoyerMoore.cs
- TextUtf8RawTextWriter.cs
- MappingModelBuildProvider.cs