Beispiel #1
0
        /// <summary>
        /// Write an error message.
        /// </summary>
        /// <param name="jsonWriter">The JSON writer to write to.</param>
        /// <param name="code">The code of the error.</param>
        /// <param name="message">The message of the error.</param>
        /// <param name="messageLanguage">The language of the message.</param>
        /// <param name="innerError">Inner error details that will be included in debug mode (if present).</param>
        private static void WriteError(JsonWriter jsonWriter, string code, string message, string messageLanguage, string innerError)
        {
            Debug.Assert(jsonWriter != null, "writer != null");
            Debug.Assert(code != null, "code != null");
            Debug.Assert(message != null, "message != null");
            Debug.Assert(messageLanguage != null, "messageLanguage != null");

            // { "error": {
            jsonWriter.StartObjectScope();
            jsonWriter.WriteName(JsonConstants.ODataErrorName);
            jsonWriter.StartObjectScope();

            // "code": "<code>"
            jsonWriter.WriteName(JsonConstants.ODataErrorCodeName);
            jsonWriter.WriteValue(code);

            // "message": {
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageName);
            jsonWriter.StartObjectScope();

            // "lang": "<messageLanguage>"
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageLanguageName);
            jsonWriter.WriteValue(messageLanguage);

            // "value": "<message>"
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageValueName);
            jsonWriter.WriteValue(message);

            // }
            jsonWriter.EndObjectScope();

            if (!string.IsNullOrEmpty(innerError))
            {
                // "innererror": {
                jsonWriter.WriteName(JsonConstants.ODataErrorInnerErrorName);
                jsonWriter.StartObjectScope();

                // Design 29: JSON error format for inner error - the inner error format is unclear, for now choosing
                //   to use the value property.
                // "value": "<innerError>"
                jsonWriter.WriteName(JsonConstants.ODataErrorMessageValueName);
                jsonWriter.WriteValue(innerError);

                // }
                jsonWriter.EndObjectScope();
            }

            // } }
            jsonWriter.EndObjectScope();
            jsonWriter.EndObjectScope();
        }
Beispiel #2
0
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="resourcePropertyType">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="version">The protocol version used for writing.</param>
        internal static void WriteComplexValue(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataComplexValue complexValue,
            ResourceType resourcePropertyType,
            bool isOpenPropertyType,
            ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            // Start the object scope which will represent the entire complex instance
            jsonWriter.StartObjectScope();

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            string typeName = complexValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the
            // type inferred from metadata
            ResourceType complexValueType = MetadataUtils.ResolveTypeName(metadata, resourcePropertyType, ref typeName, ResourceTypeKind.ComplexType, isOpenPropertyType);

            if (typeName != null)
            {
                // Write the __metadata object
                jsonWriter.WriteName(JsonConstants.ODataMetadataName);
                jsonWriter.StartObjectScope();

                // "type": "typename"
                jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                jsonWriter.WriteValue(typeName);

                // End the __metadata
                jsonWriter.EndObjectScope();
            }

            // Write the properties of the complex value as usual
            WriteProperties(jsonWriter, metadata, complexValueType, complexValue.Properties, version);

            // End the object scope which represents the complex instance
            jsonWriter.EndObjectScope();
        }
Beispiel #3
0
        /// <summary>
        /// Writes a single Uri in response to a $links query.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="baseUri">The base Uri used for writing.</param>
        /// <param name="link">The associated entity link to write out.</param>
        private static void WriteAssociatedEntityLink(JsonWriter jsonWriter, Uri baseUri, ODataAssociatedEntityLink link)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(link != null, "link != null");

            jsonWriter.StartObjectScope();
            jsonWriter.WriteName(JsonConstants.ODataUriName);
            jsonWriter.WriteValue(UriToAbsoluteUriString(link.Url, baseUri));
            jsonWriter.EndObjectScope();
        }
Beispiel #4
0
        /// <summary>
        /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="baseUri">The base Uri used for writing.</param>
        /// <param name="associatedEntityLinks">The set of associated entity links to write out.</param>
        /// <param name="includeResultsWrapper">True if the 'results' wrapper should be included into the payload; otherwise false.</param>
        private static void WriteAssociatedEntityLinks(JsonWriter jsonWriter, Uri baseUri, ODataAssociatedEntityLinks associatedEntityLinks, bool includeResultsWrapper)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(associatedEntityLinks != null, "links != null");

            if (includeResultsWrapper)
            {
                // {
                jsonWriter.StartObjectScope();
            }

            if (associatedEntityLinks.InlineCount.HasValue)
            {
                Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a count is specified.");
                jsonWriter.WriteName(JsonConstants.ODataCountName);

                jsonWriter.WriteValue(associatedEntityLinks.InlineCount.Value);
            }

            if (includeResultsWrapper)
            {
                // "results":
                jsonWriter.WriteDataArrayName();
            }

            jsonWriter.StartArrayScope();

            IEnumerable <ODataAssociatedEntityLink> entityLinks = associatedEntityLinks.Links;

            if (entityLinks != null)
            {
                foreach (ODataAssociatedEntityLink link in entityLinks)
                {
                    WriteAssociatedEntityLink(jsonWriter, baseUri, link);
                }
            }

            jsonWriter.EndArrayScope();

            if (associatedEntityLinks.NextLink != null)
            {
                // "__next": ...
                Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a next page link is specified.");
                jsonWriter.WriteName(JsonConstants.ODataNextLinkName);
                jsonWriter.WriteValue(UriUtils.UriToString(associatedEntityLinks.NextLink));
            }

            if (includeResultsWrapper)
            {
                jsonWriter.EndObjectScope();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Writes a service document in JSON format.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="defaultWorkspace">The default workspace to write in the service document.</param>
        internal static void WriteServiceDocument(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataWorkspace defaultWorkspace)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(defaultWorkspace != null, "defaultWorkspace != null");

            IEnumerable <ODataResourceCollectionInfo> collections =
                ValidationUtils.ValidateWorkspace(metadata == null ? null : metadata.ResourceSets, defaultWorkspace);

            Debug.Assert(collections != null, "collections != null");

            WriteDataWrapper(
                jsonWriter,
                true,
                () =>
            {
                // "{"
                jsonWriter.StartObjectScope();

                // "EntitySets":
                jsonWriter.WriteName(JsonConstants.ODataServiceDocumentEntitySetsName);

                // "["
                jsonWriter.StartArrayScope();

                foreach (ODataResourceCollectionInfo collectionInfo in collections)
                {
                    ValidationUtils.ValidateResourceCollectionInfo(collectionInfo);

                    // <collection name>
                    jsonWriter.WriteValue(collectionInfo.Name);
                }

                // "]"
                jsonWriter.EndArrayScope();

                // "}"
                jsonWriter.EndObjectScope();
            });
        }
Beispiel #6
0
        /// <summary>
        /// Helper method to write the data wrapper around a JSON payload.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="writingResponse">A flag indicating whether we are writing a response; data wrappers are only added to response messages.</param>
        /// <param name="payloadWriterAction">The action that writes the actual JSON payload that is being wrapped.</param>
        internal static void WriteDataWrapper(JsonWriter jsonWriter, bool writingResponse, Action payloadWriterAction)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(payloadWriterAction != null, "payloadWriterAction != null");

            if (writingResponse)
            {
                // If we're writing a response payload the entire JSON should be wrapped in { "d":  } to guard against XSS attacks
                // it makes the payload a valid JSON but invalid JScript statement.
                jsonWriter.StartObjectScope();
                jsonWriter.WriteDataWrapper();
            }

            payloadWriterAction();

            if (writingResponse)
            {
                // If we were writing a response payload the entire JSON is wrapped in an object scope, which we need to close here.
                jsonWriter.EndObjectScope();
            }
        }
Beispiel #7
0
        /// <summary>
        /// Write an <see cref="ODataProperty" /> to the given stream. This method creates an
        /// async buffered stream and writes the property to it.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="property">The property to write.</param>
        /// <param name="owningType">The type owning the property (or null if no metadata is available).</param>
        /// <param name="version">The protocol version used for writing.</param>
        /// <param name="writingResponse">Flag indicating whether a request or a response is being written.</param>
        internal static void WriteTopLevelProperty(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataProperty property,
            ResourceType owningType,
            ODataVersion version,
            bool writingResponse)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(property != null, "property != null");

            ODataJsonWriterUtils.WriteDataWrapper(
                jsonWriter,
                writingResponse,
                () =>
            {
                jsonWriter.StartObjectScope();
                WriteProperty(jsonWriter, metadata, property, owningType, version);
                jsonWriter.EndObjectScope();
            });
        }
Beispiel #8
0
        /// <summary>
        /// Writes out the value of a MultiValue property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="multiValue">The bag value to write.</param>
        /// <param name="metadataType">The metadata type for the MultiValue.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="version">The protocol version used for writing.</param>
        private static void WriteMultiValue(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataMultiValue multiValue,
            ResourceType metadataType,
            bool isOpenPropertyType,
            ODataVersion version)
        {
            Debug.Assert(multiValue != null, "multiValue != null");

            // Start the object scope which will represent the entire MultiValue instance
            jsonWriter.StartObjectScope();

            // "__metadata": { "type": "typename" }
            // If the MultiValue has type information write out the metadata and the type in it.
            string typeName = multiValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the
            // type inferred from metadata
            ResourceType multiValueType = MetadataUtils.ResolveTypeName(metadata, metadataType, ref typeName, ResourceTypeKind.MultiValue, isOpenPropertyType);

            if (typeName != null)
            {
                // Write the __metadata object
                jsonWriter.WriteName(JsonConstants.ODataMetadataName);
                jsonWriter.StartObjectScope();

                // "type": "typename"
                jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                jsonWriter.WriteValue(typeName);

                // End the __metadata
                jsonWriter.EndObjectScope();
            }

            // "results": [
            // This represents the array of items in the MultiValue
            jsonWriter.WriteDataArrayName();
            jsonWriter.StartArrayScope();

            // Iterate through the MultiValue items and write them out (treat null Items as an empty enumeration)
            IEnumerable items = multiValue.Items;

            if (items != null)
            {
                ResourceType expectedItemType = multiValueType == null ? null : ((MultiValueResourceType)multiValueType).ItemType;

                foreach (object item in items)
                {
                    ValidationUtils.ValidateMultiValueItem(item);

                    ODataComplexValue itemAsComplexValue = item as ODataComplexValue;
                    if (itemAsComplexValue != null)
                    {
                        WriteComplexValue(jsonWriter, metadata, itemAsComplexValue, expectedItemType, false, version);
                    }
                    else
                    {
                        ODataMultiValue itemAsMultiValue = item as ODataMultiValue;
                        if (itemAsMultiValue != null)
                        {
                            throw new ODataException(Strings.ODataWriter_NestedMultiValuesAreNotSupported);
                        }
                        else
                        {
                            WritePrimitiveValue(jsonWriter, item, expectedItemType);
                        }
                    }
                }
            }

            // End the array scope which holds the items
            jsonWriter.EndArrayScope();

            // End the object scope which holds the entire MultiValue
            jsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Write an <see cref="ODataProperty" /> to the given stream. This method creates an
        /// async buffered stream and writes the property to it.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="property">The property to write.</param>
        /// <param name="owningType">The type owning the property (or null if no metadata is available).</param>
        /// <param name="version">The protocol version used for writing.</param>
        /// <param name="writingResponse">Flag indicating whether a request or a response is being written.</param>
        internal static void WriteTopLevelProperty(
            JsonWriter jsonWriter, 
            DataServiceMetadataProviderWrapper metadata, 
            ODataProperty property, 
            ResourceType owningType,
            ODataVersion version, 
            bool writingResponse)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(property != null, "property != null");

            ODataJsonWriterUtils.WriteDataWrapper(
                jsonWriter,
                writingResponse,
                () =>
                {
                    jsonWriter.StartObjectScope();
                    WriteProperty(jsonWriter, metadata, property, owningType, version);
                    jsonWriter.EndObjectScope();
                });
        }
        /// <summary>
        /// Writes a single Uri in response to a $links query.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="baseUri">The base Uri used for writing.</param>
        /// <param name="link">The associated entity link to write out.</param>
        private static void WriteAssociatedEntityLink(JsonWriter jsonWriter, Uri baseUri, ODataAssociatedEntityLink link)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(link != null, "link != null");

            jsonWriter.StartObjectScope();
            jsonWriter.WriteName(JsonConstants.ODataUriName);
            jsonWriter.WriteValue(UriToAbsoluteUriString(link.Url, baseUri));
            jsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="baseUri">The base Uri used for writing.</param>
        /// <param name="associatedEntityLinks">The set of associated entity links to write out.</param>
        /// <param name="includeResultsWrapper">True if the 'results' wrapper should be included into the payload; otherwise false.</param>
        private static void WriteAssociatedEntityLinks(JsonWriter jsonWriter, Uri baseUri, ODataAssociatedEntityLinks associatedEntityLinks, bool includeResultsWrapper)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(associatedEntityLinks != null, "links != null");

            if (includeResultsWrapper)
            {
                // {
                jsonWriter.StartObjectScope();
            }

            if (associatedEntityLinks.InlineCount.HasValue)
            {
                Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a count is specified.");
                jsonWriter.WriteName(JsonConstants.ODataCountName);

                jsonWriter.WriteValue(associatedEntityLinks.InlineCount.Value);
            }

            if (includeResultsWrapper)
            {
                // "results":
                jsonWriter.WriteDataArrayName();
            }

            jsonWriter.StartArrayScope();

            IEnumerable<ODataAssociatedEntityLink> entityLinks = associatedEntityLinks.Links;
            if (entityLinks != null)
            {
                foreach (ODataAssociatedEntityLink link in entityLinks)
                {
                    WriteAssociatedEntityLink(jsonWriter, baseUri, link);
                }
            }

            jsonWriter.EndArrayScope();

            if (associatedEntityLinks.NextLink != null)
            {
                // "__next": ...
                Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a next page link is specified.");
                jsonWriter.WriteName(JsonConstants.ODataNextLinkName);
                jsonWriter.WriteValue(UriUtils.UriToString(associatedEntityLinks.NextLink));
            }

            if (includeResultsWrapper)
            {
                jsonWriter.EndObjectScope();
            }
        }
        /// <summary>
        /// Writes out the value of a MultiValue property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="multiValue">The bag value to write.</param>
        /// <param name="metadataType">The metadata type for the MultiValue.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="version">The protocol version used for writing.</param>
        private static void WriteMultiValue(
            JsonWriter jsonWriter, 
            DataServiceMetadataProviderWrapper metadata, 
            ODataMultiValue multiValue, 
            ResourceType metadataType,
            bool isOpenPropertyType,
            ODataVersion version)
        {
            Debug.Assert(multiValue != null, "multiValue != null");

            // Start the object scope which will represent the entire MultiValue instance
            jsonWriter.StartObjectScope();

            // "__metadata": { "type": "typename" }
            // If the MultiValue has type information write out the metadata and the type in it.
            string typeName = multiValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the 
            // type inferred from metadata
            ResourceType multiValueType = MetadataUtils.ResolveTypeName(metadata, metadataType, ref typeName, ResourceTypeKind.MultiValue, isOpenPropertyType);

            if (typeName != null)
            {
                // Write the __metadata object
                jsonWriter.WriteName(JsonConstants.ODataMetadataName);
                jsonWriter.StartObjectScope();

                // "type": "typename"
                jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                jsonWriter.WriteValue(typeName);

                // End the __metadata
                jsonWriter.EndObjectScope();
            }

            // "results": [
            // This represents the array of items in the MultiValue
            jsonWriter.WriteDataArrayName();
            jsonWriter.StartArrayScope();

            // Iterate through the MultiValue items and write them out (treat null Items as an empty enumeration)
            IEnumerable items = multiValue.Items;
            if (items != null)
            {
                ResourceType expectedItemType = multiValueType == null ? null : ((MultiValueResourceType)multiValueType).ItemType;

                foreach (object item in items)
                {
                    ValidationUtils.ValidateMultiValueItem(item);

                    ODataComplexValue itemAsComplexValue = item as ODataComplexValue;
                    if (itemAsComplexValue != null)
                    {
                        WriteComplexValue(jsonWriter, metadata, itemAsComplexValue, expectedItemType, false, version);
                    }
                    else
                    {
                        ODataMultiValue itemAsMultiValue = item as ODataMultiValue;
                        if (itemAsMultiValue != null)
                        {
                            throw new ODataException(Strings.ODataWriter_NestedMultiValuesAreNotSupported);
                        }
                        else
                        {
                            WritePrimitiveValue(jsonWriter, item, expectedItemType);
                        }
                    }
                }
            }

            // End the array scope which holds the items
            jsonWriter.EndArrayScope();

            // End the object scope which holds the entire MultiValue
            jsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Write an error message.
        /// </summary>
        /// <param name="jsonWriter">The JSON writer to write to.</param>
        /// <param name="code">The code of the error.</param>
        /// <param name="message">The message of the error.</param>
        /// <param name="messageLanguage">The language of the message.</param>
        /// <param name="innerError">Inner error details that will be included in debug mode (if present).</param>
        private static void WriteError(JsonWriter jsonWriter, string code, string message, string messageLanguage, string innerError)
        {
            Debug.Assert(jsonWriter != null, "writer != null");
            Debug.Assert(code != null, "code != null");
            Debug.Assert(message != null, "message != null");
            Debug.Assert(messageLanguage != null, "messageLanguage != null");

            // { "error": {
            jsonWriter.StartObjectScope();
            jsonWriter.WriteName(JsonConstants.ODataErrorName);
            jsonWriter.StartObjectScope();

            // "code": "<code>"
            jsonWriter.WriteName(JsonConstants.ODataErrorCodeName);
            jsonWriter.WriteValue(code);

            // "message": {
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageName);
            jsonWriter.StartObjectScope();

            // "lang": "<messageLanguage>"
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageLanguageName);
            jsonWriter.WriteValue(messageLanguage);

            // "value": "<message>"
            jsonWriter.WriteName(JsonConstants.ODataErrorMessageValueName);
            jsonWriter.WriteValue(message);

            // }
            jsonWriter.EndObjectScope();

            if (!string.IsNullOrEmpty(innerError))
            {
                // "innererror": {
                jsonWriter.WriteName(JsonConstants.ODataErrorInnerErrorName);
                jsonWriter.StartObjectScope();

                // Design 29: JSON error format for inner error - the inner error format is unclear, for now choosing
                //   to use the value property.
                // "value": "<innerError>"
                jsonWriter.WriteName(JsonConstants.ODataErrorMessageValueName);
                jsonWriter.WriteValue(innerError);

                // }
                jsonWriter.EndObjectScope();
            }

            // } }
            jsonWriter.EndObjectScope();
            jsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Writes a service document in JSON format.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="defaultWorkspace">The default workspace to write in the service document.</param>
        internal static void WriteServiceDocument(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataWorkspace defaultWorkspace)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(defaultWorkspace != null, "defaultWorkspace != null");

            IEnumerable<ODataResourceCollectionInfo> collections =
                ValidationUtils.ValidateWorkspace(metadata == null ? null : metadata.ResourceSets, defaultWorkspace);
            Debug.Assert(collections != null, "collections != null");

            WriteDataWrapper(
                jsonWriter,
                true,
                () =>
                {
                    // "{"
                    jsonWriter.StartObjectScope();

                    // "EntitySets":
                    jsonWriter.WriteName(JsonConstants.ODataServiceDocumentEntitySetsName);

                    // "["
                    jsonWriter.StartArrayScope();

                    foreach (ODataResourceCollectionInfo collectionInfo in collections)
                    {
                        ValidationUtils.ValidateResourceCollectionInfo(collectionInfo);

                        // <collection name>
                        jsonWriter.WriteValue(collectionInfo.Name);
                    }

                    // "]"
                    jsonWriter.EndArrayScope();

                    // "}"
                    jsonWriter.EndObjectScope();
                });
        }
        /// <summary>
        /// Writes out the value of a complex property.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="metadata">The metadata provider to use or null if no metadata is available.</param>
        /// <param name="complexValue">The complex value to write.</param>
        /// <param name="resourcePropertyType">The metadata type for the complex value.</param>
        /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param>
        /// <param name="version">The protocol version used for writing.</param>
        internal static void WriteComplexValue(
            JsonWriter jsonWriter,
            DataServiceMetadataProviderWrapper metadata,
            ODataComplexValue complexValue,
            ResourceType resourcePropertyType,
            bool isOpenPropertyType,
            ODataVersion version)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(complexValue != null, "complexValue != null");

            // Start the object scope which will represent the entire complex instance
            jsonWriter.StartObjectScope();

            // Write the "__metadata" : { "type": "typename" }
            // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely
            string typeName = complexValue.TypeName;

            // resolve the type name to the resource type; if no type name is specified we will use the 
            // type inferred from metadata
            ResourceType complexValueType = MetadataUtils.ResolveTypeName(metadata, resourcePropertyType, ref typeName, ResourceTypeKind.ComplexType, isOpenPropertyType);

            if (typeName != null)
            {
                // Write the __metadata object
                jsonWriter.WriteName(JsonConstants.ODataMetadataName);
                jsonWriter.StartObjectScope();

                // "type": "typename"
                jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName);
                jsonWriter.WriteValue(typeName);

                // End the __metadata
                jsonWriter.EndObjectScope();
            }

            // Write the properties of the complex value as usual
            WriteProperties(jsonWriter, metadata, complexValueType, complexValue.Properties, version);

            // End the object scope which represents the complex instance
            jsonWriter.EndObjectScope();
        }
        /// <summary>
        /// Helper method to write the data wrapper around a JSON payload.
        /// </summary>
        /// <param name="jsonWriter">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="writingResponse">A flag indicating whether we are writing a response; data wrappers are only added to response messages.</param>
        /// <param name="payloadWriterAction">The action that writes the actual JSON payload that is being wrapped.</param>
        internal static void WriteDataWrapper(JsonWriter jsonWriter, bool writingResponse, Action payloadWriterAction)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonWriter != null, "jsonWriter != null");
            Debug.Assert(payloadWriterAction != null, "payloadWriterAction != null");

            if (writingResponse)
            {
                // If we're writing a response payload the entire JSON should be wrapped in { "d":  } to guard against XSS attacks
                // it makes the payload a valid JSON but invalid JScript statement.
                jsonWriter.StartObjectScope();
                jsonWriter.WriteDataWrapper();
            }

            payloadWriterAction();

            if (writingResponse)
            {
                // If we were writing a response payload the entire JSON is wrapped in an object scope, which we need to close here.
                jsonWriter.EndObjectScope();
            }
        }