/// <summary>
        /// Gets the context URI for the specified ODataPayloadElement.
        /// </summary>
        /// <param name="payloadElement">The annotated payload element to get the context URI for.</param>
        /// <returns>The context URI from the annotated payload element or null if no context URI annotation exists.</returns>
        /// <remarks>If not context URI annotation is found on the <paramref name="payloadElement"/>, this
        /// method will try to compute the context URI from the expected type annotation. If successful,
        /// it will cache the computed context URI as annotation on the payload element.</remarks>
        public static string ContextUri(this ODataPayloadElement payloadElement)
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
            JsonLightContextUriAnnotation contextUriAnnotation = (JsonLightContextUriAnnotation)payloadElement.GetAnnotation(typeof(JsonLightContextUriAnnotation));

            string contextUri      = null;
            bool   cacheContextUri = false;

            // If an explicit context URI exists, return it
            if (contextUriAnnotation != null)
            {
                contextUri = contextUriAnnotation.ContextUri;
            }
            else
            {
                // Otherwise construct a context URI from the expected type annotation
                ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation =
                    (ExpectedTypeODataPayloadElementAnnotation)payloadElement.GetAnnotation(typeof(ExpectedTypeODataPayloadElementAnnotation));
                if (expectedTypeAnnotation != null)
                {
                    // Construct a context URI from the exptected type annotation
                    JsonLightMetadataDocumentUriAnnotation metadataDocumentUriAnnotation =
                        (JsonLightMetadataDocumentUriAnnotation)payloadElement.GetAnnotation(typeof(JsonLightMetadataDocumentUriAnnotation));
                    string metadataDocumentUri = metadataDocumentUriAnnotation == null
                        ? JsonLightConstants.DefaultMetadataDocumentUri.AbsoluteUri
                        : metadataDocumentUriAnnotation.MetadataDocumentUri;

                    string projectionString = null;
                    JsonLightContextUriProjectionAnnotation contextUriProjectionAnnotation = (JsonLightContextUriProjectionAnnotation)payloadElement.GetAnnotation(typeof(JsonLightContextUriProjectionAnnotation));
                    if (contextUriProjectionAnnotation != null)
                    {
                        // If we have a context URI projection, apply it to the context URI if the context URI does not already have one.
                        projectionString = contextUriProjectionAnnotation.ContextUriProjection;
                        Regex contextUriSelectExpandPattern = new Regex(@"(?:(?<!#Collection))\(.*\)");

                        // A 'null' projection string means that all properties should be projected.
                        if (projectionString != null)
                        {
                            bool hasProjection = contextUriSelectExpandPattern.IsMatch(projectionString);
                            if (!hasProjection)
                            {
                                // Inject the projection string into the context URI
                                projectionString = JsonLightConstants.ContextUriProjectionStart + projectionString + JsonLightConstants.ContextUriProjectionEnd;
                            }
                        }
                    }

                    contextUri      = BuildContextUri(payloadElement.ElementType, metadataDocumentUri, expectedTypeAnnotation, projectionString);
                    cacheContextUri = true;
                }
            }

            // Cache the computed context URI on the payload element (non-comparable annotation)
            if (cacheContextUri)
            {
                payloadElement.WithContextUri(contextUri);
                payloadElement.RemoveAnnotations(typeof(JsonLightContextUriProjectionAnnotation));
            }

            return(contextUri);
        }