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 , ready to write out a description.
///
/// 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);
}
/// 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.
/// Whether was 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 , ready to write out a description.
///
/// 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);
}
/// 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.
/// Whether was 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
- TimeIntervalCollection.cs
- PackageDigitalSignature.cs
- WorkflowInstanceProxy.cs
- XMLDiffLoader.cs
- StatusBar.cs
- SchemaImporter.cs
- RegexFCD.cs
- Thickness.cs
- XmlDocumentFragment.cs
- Border.cs
- ConditionalAttribute.cs
- PageClientProxyGenerator.cs
- ImpersonateTokenRef.cs
- StringStorage.cs
- GradientStop.cs
- Win32Exception.cs
- InputManager.cs
- CodeTypeDelegate.cs
- DesignerVerb.cs
- UseLicense.cs
- FunctionMappingTranslator.cs
- Timer.cs
- Reference.cs
- SqlStream.cs
- WebBrowserHelper.cs
- GridEntry.cs
- ListControlConvertEventArgs.cs
- AbstractDataSvcMapFileLoader.cs
- Point3DCollection.cs
- OutputCacheModule.cs
- RectangleHotSpot.cs
- HierarchicalDataSourceConverter.cs
- ConstraintConverter.cs
- XhtmlBasicTextViewAdapter.cs
- InternalDuplexBindingElement.cs
- SeverityFilter.cs
- InstalledFontCollection.cs
- FormsAuthenticationTicket.cs
- PipelineModuleStepContainer.cs
- ArrayConverter.cs
- TimestampInformation.cs
- ComponentCollection.cs
- EditorZone.cs
- BooleanExpr.cs
- SpotLight.cs
- CachedFontFamily.cs
- ObjectItemAttributeAssemblyLoader.cs
- RelatedView.cs
- ComponentDispatcherThread.cs
- ProfileService.cs
- WindowsHyperlink.cs
- ListDictionaryInternal.cs
- _DisconnectOverlappedAsyncResult.cs
- StaticContext.cs
- CustomTypeDescriptor.cs
- PointConverter.cs
- WorkflowElementDialog.cs
- CheckBox.cs
- RouteData.cs
- MenuItemBindingCollection.cs
- EntityViewGenerationConstants.cs
- RepeatBehavior.cs
- MessageVersionConverter.cs
- SoapParser.cs
- RIPEMD160.cs
- FormatterServices.cs
- XmlSubtreeReader.cs
- ImageAnimator.cs
- CompilerParameters.cs
- ApplicationInfo.cs
- PageThemeCodeDomTreeGenerator.cs
- MarginsConverter.cs
- SqlEnums.cs
- WebMessageEncodingElement.cs
- ArrayMergeHelper.cs
- PeerCollaboration.cs
- BuildManagerHost.cs
- SqlDataSourceFilteringEventArgs.cs
- Sequence.cs
- Transform3DGroup.cs
- Visitor.cs
- ButtonDesigner.cs
- ConnectionsZone.cs
- XmlTextReaderImpl.cs
- ContentDefinition.cs
- Selection.cs
- TemplateBuilder.cs
- FormParameter.cs
- XMLDiffLoader.cs
- Types.cs
- StoreContentChangedEventArgs.cs
- DataGridTextBoxColumn.cs
- FrugalList.cs
- DataControlImageButton.cs
- SeparatorAutomationPeer.cs
- Processor.cs
- ScrollItemPattern.cs
- milrender.cs
- SymDocumentType.cs
- SerialStream.cs