/// <summary>
        /// Writes an operation (an action or a function).
        /// </summary>
        /// <param name="operation">The association link to write.</param>
        internal void WriteOperation(ODataOperation operation)
        {
            DebugUtils.CheckNoExternalCallers();

            // checks for null and validates its properties
            WriterValidationUtils.ValidateCanWriteOperation(operation, this.WritingResponse);
            ValidationUtils.ValidateOperationMetadataNotNull(operation);
            ValidationUtils.ValidateOperationTargetNotNull(operation);

            string elementName;

            if (operation is ODataAction)
            {
                elementName = AtomConstants.ODataActionElementName;
            }
            else
            {
                Debug.Assert(operation is ODataFunction, "operation is either an ODataAction or an ODataFunction");
                elementName = AtomConstants.ODataFunctionElementName;
            }

            // <m:action ... or <m:function ...
            this.XmlWriter.WriteStartElement(
                AtomConstants.ODataMetadataNamespacePrefix,
                elementName,
                AtomConstants.ODataMetadataNamespace);

            // write the attributes of the action/function

            // The metadata URI of an ODataOperation can be relative.
            string metadataAttributeValue = this.UriToUrlAttributeValue(operation.Metadata, /*failOnRelativeUriWithoutBaseUri*/ false);

            this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationMetadataAttribute, metadataAttributeValue);

            if (operation.Title != null)
            {
                this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationTitleAttribute, operation.Title);
            }

            string targetAttribute = this.UriToUrlAttributeValue(operation.Target);

            this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationTargetAttribute, targetAttribute);

            // </m:action> or </m:function>
            this.XmlWriter.WriteEndElement();
        }
        /// <summary>
        /// Writes "actions" or "functions" metadata.
        /// </summary>
        /// <param name="operations">The operations to write.</param>
        /// <param name="operationName">The name of the property used for the operations.</param>
        /// <param name="isAction">true when writing the entry's actions; false when writing the entry's functions.</param>
        /// <param name="writingJsonLight">true if we're writing JSON lite, false if we're writing verbose JSON.</param>
        internal void WriteOperations(IEnumerable <ODataOperation> operations, string operationName, bool isAction, bool writingJsonLight)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(operationName != null, "operationName != null");

            bool firstOperation = true;

            // we cannot compare two URI's directly because the 'Equals' method on the 'Uri' class compares two 'Uri' instances without regard to the
            // fragment part of the URI. (E.G: For 'http://someuri/index.htm#EC.action1' and http://someuri/index.htm#EC.action2', the 'Equals' method
            // will return true.
            var metadataGroups = operations.GroupBy(o =>
            {
                // We need to validate here to ensure that the metadata is not null, otherwise call to the method 'UriToString' will throw.
                ValidationUtils.ValidateOperationNotNull(o, isAction);
                WriterValidationUtils.ValidateCanWriteOperation(o, this.VerboseJsonOutputContext.WritingResponse);
                ValidationUtils.ValidateOperationMetadataNotNull(o);
                if (!writingJsonLight)
                {
                    ValidationUtils.ValidateOperationTargetNotNull(o);
                }

                return(this.UriToUriString(o.Metadata, /*makeAbsolute*/ false));
            });

            foreach (IGrouping <string, ODataOperation> metadataGroup in metadataGroups)
            {
                if (firstOperation)
                {
                    // write the the object only if there is any operations.
                    this.VerboseJsonOutputContext.JsonWriter.WriteName(operationName);
                    this.VerboseJsonOutputContext.JsonWriter.StartObjectScope();
                    firstOperation = false;
                }

                this.WriteOperationMetadataGroup(metadataGroup);
            }

            // close the object if there is any operations.
            if (!firstOperation)
            {
                this.VerboseJsonOutputContext.JsonWriter.EndObjectScope();
            }
        }
        /// <summary>
        /// Writes "actions" or "functions" metadata.
        /// </summary>
        /// <param name="operations">The operations to write.</param>
        /// <param name="isAction">true when writing the resource's actions; false when writing the resource's functions.</param>
        internal void WriteOperations(IEnumerable <ODataOperation> operations, bool isAction)
        {
            // We cannot compare two URIs directly because the 'Equals' method on the 'Uri' class compares two 'Uri' instances without regard to the
            // fragment part of the URI. (E.G: For 'http://someuri/index.htm#EC.action1' and http://someuri/index.htm#EC.action2', the 'Equals' method
            // will return true.
            IEnumerable <IGrouping <string, ODataOperation> > metadataGroups = operations.GroupBy(o =>
            {
                // We need to validate here to ensure that the metadata is not null, otherwise call to the method 'UriToString' will throw.
                ValidationUtils.ValidateOperationNotNull(o, isAction);
                WriterValidationUtils.ValidateCanWriteOperation(o, this.JsonLightOutputContext.WritingResponse);
                ODataJsonLightValidationUtils.ValidateOperation(this.MetadataDocumentBaseUri, o);
                return(this.GetOperationMetadataString(o));
            });

            foreach (IGrouping <string, ODataOperation> metadataGroup in metadataGroups)
            {
                this.WriteOperationMetadataGroup(metadataGroup);
            }
        }