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 / 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
- TreeWalker.cs
- ToolboxItemImageConverter.cs
- InputScopeManager.cs
- XmlConvert.cs
- LocatorManager.cs
- PenLineCapValidation.cs
- RegexCompilationInfo.cs
- LineUtil.cs
- CatalogPartChrome.cs
- _ConnectOverlappedAsyncResult.cs
- ThreadPool.cs
- StreamInfo.cs
- SplineKeyFrames.cs
- StackOverflowException.cs
- DateTime.cs
- XAMLParseException.cs
- EntityDataSourceSelectedEventArgs.cs
- UpdatePanelControlTrigger.cs
- TemplateKey.cs
- EventSinkActivity.cs
- ChildTable.cs
- DataSourceControlBuilder.cs
- AnnotationAuthorChangedEventArgs.cs
- DashStyle.cs
- BamlReader.cs
- EntityClientCacheKey.cs
- BitmapEffectInputConnector.cs
- CompilationPass2Task.cs
- CommandHelpers.cs
- ActivityDesignerHighlighter.cs
- ComEventsHelper.cs
- PingReply.cs
- QuaternionKeyFrameCollection.cs
- ControlsConfig.cs
- HtmlInputRadioButton.cs
- HostedElements.cs
- CompositeActivityValidator.cs
- MarshalByValueComponent.cs
- FileDialog.cs
- AddInController.cs
- DataGridViewHitTestInfo.cs
- DisableDpiAwarenessAttribute.cs
- XmlNodeComparer.cs
- TextPointer.cs
- TabletCollection.cs
- ObjectQueryExecutionPlan.cs
- NativeCompoundFileAPIs.cs
- FixedSOMTableRow.cs
- WebConfigurationManager.cs
- CodeComment.cs
- TextServicesProperty.cs
- XmlParserContext.cs
- FaultFormatter.cs
- DynamicContractTypeBuilder.cs
- CodeTypeDeclarationCollection.cs
- TypeBrowserDialog.cs
- ErrorHandler.cs
- MethodSignatureGenerator.cs
- XDeferredAxisSource.cs
- EntityProviderFactory.cs
- IndexedWhereQueryOperator.cs
- HwndSubclass.cs
- SystemUdpStatistics.cs
- securitymgrsite.cs
- WebDisplayNameAttribute.cs
- SqlDataSourceCommandEventArgs.cs
- ObjectListComponentEditor.cs
- HttpClientCertificate.cs
- TypeDescriptor.cs
- ServiceContractListItemList.cs
- CngUIPolicy.cs
- ManifestResourceInfo.cs
- PerformanceCounterCategory.cs
- COAUTHINFO.cs
- CheckBoxFlatAdapter.cs
- ProtocolsSection.cs
- xmlglyphRunInfo.cs
- DataGridPagerStyle.cs
- Region.cs
- FlowchartSizeFeature.cs
- HttpCapabilitiesEvaluator.cs
- TextTreeRootNode.cs
- AspNetHostingPermission.cs
- QuotedPairReader.cs
- EndpointInfo.cs
- SHA512CryptoServiceProvider.cs
- CodeTypeParameter.cs
- OleDbErrorCollection.cs
- RepeatInfo.cs
- UnknownWrapper.cs
- ExpressionBindingCollection.cs
- EventEntry.cs
- ConsumerConnectionPoint.cs
- MemberPathMap.cs
- CapabilitiesUse.cs
- WindowsListViewItem.cs
- MenuItemCollection.cs
- WebScriptEnablingBehavior.cs
- WorkflowMarkupSerializerMapping.cs
- WindowPattern.cs