/// <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);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Initializes a new instance of the CommonExpressionEvaluatingVisitor class.
 /// </summary>
 /// <param name="dataSet">The data set.</param>
 protected CommonExpressionEvaluatingVisitor(IQueryDataSet dataSet)
 {
     ExceptionUtilities.CheckArgumentNotNull(dataSet, "dataSet");
     this.dataSet = dataSet;
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Initializes a new instance of the ODataRequest class
 /// </summary>
 /// <param name="uriToStringConverter">The OData uri to string converter to use when sending the request</param>
 /// <param name="requestManager">The IODataRequestManager used for building the ODataRequest (which is needed for cloning)</param>
 internal ODataRequest(IODataUriToStringConverter uriToStringConverter, IODataRequestManager requestManager = null)
 {
     ExceptionUtilities.CheckArgumentNotNull(uriToStringConverter, "uriToStringConverter");
     this.uriToStringConverter = uriToStringConverter;
     this.RequestManager       = requestManager;
 }
 /// <summary>
 /// Visits the specified json object.
 /// </summary>
 /// <param name="jsonObject">The json object.</param>
 /// <returns>The converted object</returns>
 public object Visit(JsonObject jsonObject)
 {
     ExceptionUtilities.CheckArgumentNotNull(jsonObject, "jsonObject");
     return(jsonObject.Properties.ToDictionary(p => p.Name, p => p.Value.Accept(this)));
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Tries to get the 'boundary' portion of the given mime-part's content-type
 /// </summary>
 /// <param name="mimePart">The mime part to get the boundary for</param>
 /// <param name="boundary">The boundary if its value is found</param>
 /// <returns>Whether or not the boundary was found</returns>
 public static bool TryGetMimeBoundary(this IMimePart mimePart, out string boundary)
 {
     ExceptionUtilities.CheckArgumentNotNull(mimePart, "mimePart");
     return(mimePart.TryGetContentTypeParameter(HttpHeaders.Boundary, out boundary));
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Extension method to perform sync/async version of DataServiceContext.ExecuteBatch dynamically
 /// </summary>
 /// <param name="context">The context to call execute batch on</param>
 /// <param name="continuation">The asynchronous continuation</param>
 /// <param name="async">A value indicating whether or not to use async API</param>
 /// <param name="queries">The queries to execute</param>
 /// <param name="onCompletion">A callback for when the call completes</param>
 public static void ExecuteBatch(this WrappedDataServiceContext context, IAsyncContinuation continuation, bool async, WrappedArray <WrappedDataServiceRequest> queries, Action <WrappedDataServiceResponse> onCompletion)
 {
     ExceptionUtilities.CheckArgumentNotNull(context, "context");
     AsyncHelpers.InvokeSyncOrAsyncMethodCall <WrappedDataServiceResponse>(continuation, async, () => context.ExecuteBatch(queries), c => context.BeginExecuteBatch(c, null, queries), r => context.EndExecuteBatch(r), onCompletion);
 }
 /// <summary>
 /// Visits the specified primitive.
 /// </summary>
 /// <param name="primitive">The primitive.</param>
 /// <returns>The converted object</returns>
 public object Visit(JsonPrimitiveValue primitive)
 {
     ExceptionUtilities.CheckArgumentNotNull(primitive, "primitive");
     return(primitive.Value);
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Annotates the payload element with delta atom:link values.
        /// </summary>
        /// <param name="payloadElement">The payload element to annotate.</param>
        /// <param name="href">The value of the atom:link's href property</param>
        /// <param name="type">The value of the atom:link's type property</param>
        /// <param name="hrefLang">The optional value of the atom:link's hrefLang property</param>
        /// <param name="title">The optional value of the atom:link's title property</param>
        /// <param name="length">The optional value of the atom:link's length property</param>
        /// <returns>The payload element with the annotation applied.</returns>
        public static T AtomDeltaLink <T>(this T payloadElement, string href, string type, string hrefLang = null, string title = null, string length = null) where T : ODataPayloadElement
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            return(payloadElement.AtomLink(href, TestAtomConstants.AtomDeltaRelationAttributeValue, type, hrefLang, title, length));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Annotates the feed with atom:subtitle values.
        /// </summary>
        /// <param name="feed">The feed to annotate.</param>
        /// <param name="subtitleValue">The value of the atom:subtitle element.</param>
        /// <param name="subtitleValueType">The type of the atom:subtitle value.</param>
        /// <returns>The feed with the annotation applied.</returns>
        public static EntitySetInstance AtomSubtitle(this EntitySetInstance feed, string subtitleValue, string subtitleValueType)
        {
            ExceptionUtilities.CheckArgumentNotNull(feed, "feed");

            return(feed.AtomText(TestAtomConstants.AtomSubtitleElementName, subtitleValue, subtitleValueType));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Annotates the payload element with atom:contributor values.
        /// </summary>
        /// <param name="payloadElement">The payload element to annotate.</param>
        /// <param name="name">The value of the atom:contributor's name property.</param>
        /// <param name="uri">The value of the atom:contributor's URI property.</param>
        /// <param name="email">The value of the atom:contributor's email address property.</param>
        /// <returns>The payload element with the annotation applied.</returns>
        public static T AtomContributor <T>(this T payloadElement, string name, string uri, string email) where T : ODataPayloadElement
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            return(payloadElement.AtomPerson(TestAtomConstants.AtomContributorElementName, name, uri, email));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Annotates the entry with edit atom:link values.
        /// </summary>
        /// <param name="entry">The entry to annotate.</param>
        /// <param name="href">The value of the atom:link's href property</param>
        /// <param name="type">The value of the atom:link's type property</param>
        /// <param name="hrefLang">The optional value of the atom:link's hrefLang property</param>
        /// <param name="title">The optional value of the atom:link's title property</param>
        /// <param name="length">The optional value of the atom:link's length property</param>
        /// <returns>The entry with the annotation applied.</returns>
        public static EntityInstance AtomEditLink(this EntityInstance entry, string href, string type, string hrefLang = null, string title = null, string length = null)
        {
            ExceptionUtilities.CheckArgumentNotNull(entry, "entry");

            return(entry.AtomLink(href, TestAtomConstants.AtomEditRelationAttributeValue, type, hrefLang, title, length));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Annotates the payload element with atom:category value with the type name scheme.
        /// </summary>
        /// <param name="payloadElement">The payload element to annotate.</param>
        /// <param name="term">The value of the atom:category's term property.</param>
        /// <param name="label">The value of the atom:category's label property.</param>
        /// <returns>The payload element with the annotation applied.</returns>
        public static T AtomCategoryWithTypeName <T>(this T payloadElement, string term, string label) where T : ODataPayloadElement
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            return(payloadElement.AtomCategory(term, TestAtomConstants.ODataSchemeNamespace, label));
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Gets the data type of a property value specified in the property instance payload element.
 /// </summary>
 /// <param name="propertyInstance">The property instance payload element to inspect.</param>
 /// <returns>The data type of the property value (can be used to define the metadata for this property).</returns>
 public static IEdmTypeReference GetPayloadElementPropertyValueType(IEdmStructuralProperty propertyInstance)
 {
     ExceptionUtilities.CheckArgumentNotNull(propertyInstance, "propertyInstance");
     return(propertyInstance.Type);
 }
Ejemplo n.º 14
0
        /// <summary>
        /// Creates a new action import with the specified name.
        /// </summary>
        /// <param name="container">The <see cref="EntityContainer"/> to create the action import in.</param>
        /// <param name="localName">The name for the action import to create.</param>
        /// <returns>The newly created action import instance.</returns>
        public static EdmActionImport ActionImport(this EdmEntityContainer container, IEdmAction action)
        {
            ExceptionUtilities.CheckArgumentNotNull(container, "container");

            return(container.AddActionImport(action));
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Extension method to perform sync/async version of DataServiceContext.Execute dynamically
 /// </summary>
 /// <typeparam name="TElement">The element type of the wrapped query results</typeparam>
 /// <param name="context">The context to call execute on</param>
 /// <param name="continuation">The asynchronous continuation</param>
 /// <param name="async">A value indicating whether or not to use async API</param>
 /// <param name="elementType">The element type of the query results</param>
 /// <param name="requestUri">The uri to make a request to</param>
 /// <param name="onCompletion">A callback for when the call completes</param>
 public static void Execute <TElement>(this WrappedDataServiceContext context, IAsyncContinuation continuation, bool async, Type elementType, Uri requestUri, Action <WrappedIEnumerable <TElement> > onCompletion) where TElement : WrappedObject
 {
     ExceptionUtilities.CheckArgumentNotNull(context, "context");
     AsyncHelpers.InvokeSyncOrAsyncMethodCall <WrappedIEnumerable <TElement> >(continuation, async, () => context.Execute <TElement>(elementType, requestUri), c => context.BeginExecute <TElement>(elementType, requestUri, c, null), r => context.EndExecute <TElement>(elementType, r), onCompletion);
 }
Ejemplo n.º 16
0
        /// <summary>
        /// Annotates the entry with atom:summary values.
        /// </summary>
        /// <param name="entry">The entry to annotate.</param>
        /// <param name="summaryValue">The value of the atom:summary element.</param>
        /// <param name="summaryValueType">The type of the atom:summary value.</param>
        /// <returns>The entry with the annotation applied.</returns>
        public static EntityInstance AtomSummary(this EntityInstance entry, string summaryValue, string summaryValueType)
        {
            ExceptionUtilities.CheckArgumentNotNull(entry, "entry");

            return(entry.AtomText(TestAtomConstants.AtomSummaryElementName, summaryValue, summaryValueType));
        }
Ejemplo n.º 17
0
 /// <summary>
 /// Creates a query using the clr type and entity set from the given query entity type
 /// </summary>
 /// <typeparam name="TElement">The wrapped element type of the query</typeparam>
 /// <param name="context">The wrapped context</param>
 /// <param name="queryEntityType">The query entity type</param>
 /// <returns>The query created using the clr type and entity set name from the query type</returns>
 public static WrappedDataServiceQuery <TElement> CreateQuery <TElement>(this WrappedDataServiceContext context, QueryEntityType queryEntityType) where TElement : WrappedObject
 {
     ExceptionUtilities.CheckArgumentNotNull(context, "context");
     ExceptionUtilities.CheckArgumentNotNull(queryEntityType, "queryEntityType");
     return(context.CreateQuery <TElement>(queryEntityType.ClrType, queryEntityType.EntitySet.Name));
 }
Ejemplo n.º 18
0
        /// <summary>
        /// Annotates the payload element with atom:title values.
        /// </summary>
        /// <param name="payloadElement">The payload element to annotate.</param>
        /// <param name="subtitleValue">The value of the atom:title element.</param>
        /// <param name="subtitleValueType">The type of the atom:title value.</param>
        /// <returns>The payload element with the annotation applied.</returns>
        public static T AtomTitle <T>(this T payloadElement, string titleValue, string titleValueType) where T : ODataPayloadElement
        {
            ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");

            return(payloadElement.AtomText(TestAtomConstants.AtomTitleElementName, titleValue, titleValueType));
        }
 /// <summary>
 /// Visits the specified json array.
 /// </summary>
 /// <param name="jsonArray">The json array.</param>
 /// <returns>The converted object</returns>
 public object Visit(JsonArray jsonArray)
 {
     ExceptionUtilities.CheckArgumentNotNull(jsonArray, "jsonArray");
     return(jsonArray.Elements.Select(e => e.Accept(this)));
 }
Ejemplo n.º 20
0
 /// <summary>
 /// Returns true if the specified clr type is spatial, false otherwise.
 /// </summary>
 /// <param name="clrType">The clr type to check.</param>
 /// <returns>Value indicating whether the specified clr type is spatial.</returns>
 public bool IsSpatial(Type clrType)
 {
     ExceptionUtilities.CheckArgumentNotNull(clrType, "clrType");
     return(typeof(ISpatial).IsAssignableFrom(clrType));
 }
 /// <summary>
 /// Converts the specified json object into a dictionary.
 /// </summary>
 /// <param name="jsonObject">The json object to convert.</param>
 /// <returns>The converted dictionary</returns>
 public IDictionary <string, object> Convert(JsonObject jsonObject)
 {
     ExceptionUtilities.CheckArgumentNotNull(jsonObject, "jsonObject");
     return((IDictionary <string, object>) new JsonToDictionaryConvertingVisitor().Visit(jsonObject));
 }
Ejemplo n.º 22
0
 /// <summary>
 /// Initializes a new instance of the DictionaryResourceLookup class.
 /// </summary>
 /// <param name="dictionary">The dictionary containing the resource strings.</param>
 public DictionaryResourceLookup(IDictionary <string, string> dictionary)
 {
     ExceptionUtilities.CheckArgumentNotNull(dictionary, "dictionary");
     this.dictionary = dictionary;
 }
Ejemplo n.º 23
0
 /// <summary>
 /// Adds the given sequence of key-value pairs to the dictionary.
 /// </summary>
 /// <typeparam name="TKey">The type of the keys</typeparam>
 /// <typeparam name="TValue">The type of the values</typeparam>
 /// <param name="dictionary">The dictionary to add to</param>
 /// <param name="values">The key-value pairs to add</param>
 public static void AddRange <TKey, TValue>(this IDictionary <TKey, TValue> dictionary, IEnumerable <KeyValuePair <TKey, TValue> > values)
 {
     ExceptionUtilities.CheckArgumentNotNull(dictionary, "dictionary");
     ExceptionUtilities.CheckArgumentNotNull(values, "values");
     values.ForEach(v => dictionary.Add(v));
 }
Ejemplo n.º 24
0
 /// <summary>
 /// Initializes a new instance of the SentenceStringGenerator class.
 /// </summary>
 /// <param name="wordGenerator">The word generator.</param>
 public SentenceStringGenerator(IStringGenerator wordGenerator)
 {
     ExceptionUtilities.CheckArgumentNotNull(wordGenerator, "wordGenerator");
     this.wordGenerator = wordGenerator;
 }
Ejemplo n.º 25
0
 /// <summary>
 /// Tries to get the 'charset' portion of the given mime-part's content-type
 /// </summary>
 /// <param name="mimePart">The mime part to get the charset for</param>
 /// <param name="charset">The charset if its value is found</param>
 /// <returns>Whether or not the charset was found</returns>
 public static bool TryGetMimeCharset(this IMimePart mimePart, out string charset)
 {
     ExceptionUtilities.CheckArgumentNotNull(mimePart, "mimePart");
     return(mimePart.TryGetContentTypeParameter(HttpHeaders.Charset, out charset));
 }
Ejemplo n.º 26
0
 /// <summary>
 /// Extension method to perform sync/async version of DataServiceQuery.Execute dynamically
 /// </summary>
 /// <typeparam name="TElement">The element type of the wrapped results</typeparam>
 /// <param name="query">The query to execute</param>
 /// <param name="continuation">The asynchronous continuation</param>
 /// <param name="async">A value indicating whether or not to use async API</param>
 /// <param name="onCompletion">A callback for when the call completes</param>
 public static void Execute <TElement>(this WrappedDataServiceQuery <TElement> query, IAsyncContinuation continuation, bool async, Action <WrappedIEnumerable <TElement> > onCompletion) where TElement : WrappedObject
 {
     ExceptionUtilities.CheckArgumentNotNull(query, "query");
     AsyncHelpers.InvokeSyncOrAsyncMethodCall <WrappedIEnumerable <TElement> >(continuation, async, () => query.Execute(), c => query.BeginExecute(c, null), r => query.EndExecute(r), onCompletion);
 }
 /// <summary>
 /// Deserializes the given binary payload as a primitive binary value
 /// </summary>
 /// <param name="serialized">The serialized value</param>
 /// <param name="payloadContext">Additional payload information to aid deserialization</param>
 /// <returns>A primitive value containing the binary payload</returns>
 public override ODataPayloadElement DeserializeFromBinary(byte[] serialized, ODataPayloadContext payloadContext)
 {
     ExceptionUtilities.CheckArgumentNotNull(serialized, "serialized");
     return(new PrimitiveValue(null, serialized));
 }
Ejemplo n.º 28
0
 /// <summary>
 /// Extension method to perform sync/async version of DataServiceContext.LoadProperty dynamically
 /// </summary>
 /// <param name="context">The context to call call load property on</param>
 /// <param name="continuation">The asynchronous continuation</param>
 /// <param name="async">A value indicating whether or not to use async API</param>
 /// <param name="entity">The entity to load a property on</param>
 /// <param name="propertyName">The name of the property to load</param>
 /// <param name="onCompletion">A callback for when the call completes</param>
 public static void LoadProperty(this WrappedDataServiceContext context, IAsyncContinuation continuation, bool async, WrappedEntityInstance entity, string propertyName, Action <WrappedQueryOperationResponse> onCompletion)
 {
     ExceptionUtilities.CheckArgumentNotNull(context, "context");
     AsyncHelpers.InvokeSyncOrAsyncMethodCall <WrappedQueryOperationResponse>(continuation, async, () => context.LoadProperty(entity, propertyName), c => context.BeginLoadProperty(entity, propertyName, c, null), r => context.EndLoadProperty(r), onCompletion);
 }
Ejemplo n.º 29
0
        /// <summary>
        /// Generates a set of values for an entity type's key properties. Will throw if any key property is a dependent/foreign-key. For composite keys, only one of the values is guaranteed to be unique.
        /// </summary>
        /// <param name="set">The entity set the type belongs to</param>
        /// <param name="type">The entity type to generate a key for</param>
        /// <returns>The key property values in metadata order</returns>
        protected internal IEnumerable <NamedValue> GeneratePropertyValuesWithUniqueKey(EntitySet set, EntityType type)
        {
            ExceptionUtilities.CheckArgumentNotNull(set, "set");
            ExceptionUtilities.CheckArgumentNotNull(type, "type");

            AssertPrimaryKeyHasNoReferentialConstraints(type);

            // get the key property names
            var keyPropertyNames = type.AllKeyProperties.Select(p => p.Name).ToList();

            // get the existing values for the key properties
            var existingValues = this.GetExistingPrimitivePropertyValues(set, keyPropertyNames);

            // generate an initial set of values
            var generatedValues = this.GeneratePropertyValues(set, type);

            // allocate storage for the key values we find. Note that we will generate them in random order, then reorder them later.
            // Doing it this way so that the 1st property is not the one that must be unique for composite keys
            var uniqueValues = new Dictionary <string, object>();

            // loop through the key property names in random order
            // if a unique value is found, then there is no need to check for the rest
            bool keyIsUnique = false;

            while (keyPropertyNames.Any())
            {
                // pick a random property name
                var propertyName = this.Random.ChooseFrom(keyPropertyNames);
                keyPropertyNames.Remove(propertyName);

                // only retry one more time than there are values, since by then we really should have found something
                var tries = existingValues[propertyName].Count + 1;

                // regenerate property values until a unique value is found for this property
                var value = generatedValues.Single(v => v.Name == propertyName).Value;
                while (!keyIsUnique && tries-- > 0)
                {
                    keyIsUnique = !existingValues[propertyName].Any(v => ValueComparer.Instance.Equals(v, value));
                    if (!keyIsUnique)
                    {
                        generatedValues = this.GeneratePropertyValues(set, type);
                        value           = generatedValues.Single(v => v.Name == propertyName).Value;
                    }
                }

                // even if we did not find a unique value for this property, we should populate it, because another property
                // may result in the key being unique later on
                uniqueValues[propertyName] = value;
            }

            // if we could not generate a unique key, throw an exception
            ExceptionUtilities.Assert(keyIsUnique, "Could not generate a unique key for type '{0}'", type.FullName);

            if (!type.Annotations.OfType <HasStreamAnnotation>().Any())
            {
                // add in the non-key values
                foreach (var value in generatedValues)
                {
                    if (!uniqueValues.ContainsKey(value.Name))
                    {
                        uniqueValues[value.Name] = value.Value;
                    }
                }
            }

            // return them in metadata order
            return(type.AllProperties.SelectMany(p => uniqueValues.Where(pair => pair.Key.Split('.').First().Equals(p.Name)).Select(pair => new NamedValue(pair.Key, pair.Value))));
        }
        /// <summary>
        /// Builds a context URI from the expected type annotation.
        /// </summary>
        /// <param name="payloadElementKind">The payload element kind to build the context URI for.</param>
        /// <param name="metadataDocumentUri">The metadata document URI.</param>
        /// <param name="expectedTypeAnnotation">The expected type annotation.</param>
        /// <returns>The constructed context URI.</returns>
        public static string BuildContextUri(ODataPayloadElementType payloadElementKind, string metadataDocumentUri, ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, string projectionString = null)
        {
            ExceptionUtilities.CheckArgumentNotNull(metadataDocumentUri, "metadataDocumentUri");
            ExceptionUtilities.CheckArgumentNotNull(expectedTypeAnnotation, "expectedTypeAnnotation");

            StringBuilder builder = new StringBuilder(metadataDocumentUri);

            switch (payloadElementKind)
            {
            // Entry payload
            case ODataPayloadElementType.EntityInstance:
            {
                EdmEntitySet entitySet = (EdmEntitySet)expectedTypeAnnotation.EdmEntitySet;
                ExceptionUtilities.Assert(entitySet != null, "Entity set is required for entry payloads.");

                builder.Append('#');
                AppendEntityContainerElement(builder, entitySet.Container, entitySet.Name);
                AppendTypeCastIfNeeded(builder, entitySet, expectedTypeAnnotation.EdmExpectedType.Definition);
                builder.Append(projectionString);
                builder.Append("/$entity");

                break;
            }

            // Feed payload
            case ODataPayloadElementType.EntitySetInstance:
            {
                EdmEntitySet entitySet = (EdmEntitySet)expectedTypeAnnotation.EdmEntitySet;
                ExceptionUtilities.Assert(entitySet != null, "Entity set is required for feed payloads.");
                builder.Append('#');
                AppendEntityContainerElement(builder, entitySet.Container, entitySet.Name);
                AppendTypeCastIfNeeded(builder, entitySet, expectedTypeAnnotation.EdmExpectedType.Definition);
                builder.Append(projectionString);

                break;
            }

            // Property payload
            case ODataPayloadElementType.PrimitiveProperty:                 // fall through
            case ODataPayloadElementType.PrimitiveMultiValueProperty:       // fall through
            case ODataPayloadElementType.ComplexMultiValueProperty:         // fall through
            case ODataPayloadElementType.ComplexProperty:                   // fall through
            case ODataPayloadElementType.NullPropertyInstance:
            // Collection payload
            case ODataPayloadElementType.EmptyCollectionProperty:       // fall through
            case ODataPayloadElementType.ComplexInstanceCollection:     // fall through
            case ODataPayloadElementType.PrimitiveCollection:
                builder.Append('#');

                // NOTE: property payloads can be produced by regular properties as well as function imports
                IEdmTypeReference edmExpectedType = null;
                if (expectedTypeAnnotation.EdmProperty != null)
                {
                    edmExpectedType = expectedTypeAnnotation.EdmProperty.Type;
                }
                else if (expectedTypeAnnotation.ProductFunctionImport != null)
                {
                    edmExpectedType = expectedTypeAnnotation.ProductFunctionImport.Operation.ReturnType;
                }
                else if (expectedTypeAnnotation.EdmExpectedType != null)
                {
                    edmExpectedType = expectedTypeAnnotation.EdmExpectedType;
                }

                if (edmExpectedType == null)
                {
                    if (expectedTypeAnnotation.EdmExpectedType != null)
                    {
                        AppendTypeName(builder, expectedTypeAnnotation.EdmExpectedType.Definition);
                    }
                    else if (expectedTypeAnnotation.ProductFunctionImport != null)
                    {
                        AppendTypeName(builder, expectedTypeAnnotation.ProductFunctionImport.Operation.ReturnType.Definition);
                    }
                }
                else
                {
                    AppendTypeName(builder, edmExpectedType.Definition);
                }

                break;

            // Entity reference link payload
            case ODataPayloadElementType.DeferredLink:
            case ODataPayloadElementType.LinkCollection:
            {
                IEdmEntitySet         entitySet          = expectedTypeAnnotation.EdmEntitySet;
                EdmNavigationProperty navigationProperty = expectedTypeAnnotation.EdmNavigationProperty as EdmNavigationProperty;
                IEdmEntityType        entityType         = navigationProperty.DeclaringType as IEdmEntityType;

                ExceptionUtilities.Assert(entitySet != null, "entitySet is required for entity reference link payloads.");
                ExceptionUtilities.Assert(navigationProperty != null, "Navigation property is required for entity reference link payloads.");

                builder.Append('#');

                if (payloadElementKind == ODataPayloadElementType.DeferredLink)
                {
                    builder.Append("$ref");
                }
                else if (payloadElementKind == ODataPayloadElementType.LinkCollection)
                {
                    builder.Append("Collection($ref)");
                }

                break;
            }

            // Service document payload
            case ODataPayloadElementType.ServiceDocumentInstance:       // fall through
            case ODataPayloadElementType.WorkspaceInstance:
                // NOTE: the builder already contains the metadata document URI.
                break;

            default:
                return(null);
            }

            return(builder.ToString());
        }