/// <summary>
        /// Gets the type and uri specified in the metadata object in the given json object.
        /// </summary>
        /// <param name="jsonObjectTable">jsonObject which contains the metadata information</param>
        /// <param name="expectedType">expected type that this segment of the uri is targeted to</param>
        /// <param name="topLevel">whether the segment represents the top level object.</param>
        /// <param name="uri">uri as specified in the metadata object. If its not specified, this is set to null</param>
        /// <param name="metadataElementSpecified">returns true if the metadata element was specified</param>
        /// <returns>typename and uri as specified in the metadata object</returns>
        private ResourceType GetTypeAndUriFromMetadata(
            Dictionary <String, Object> jsonObjectTable,
            ResourceType expectedType,
            bool topLevel,
            out string uri,
            out bool metadataElementSpecified)
        {
            metadataElementSpecified = false;

            // Get the metadata object
            object       metadataObject;
            ResourceType targetType        = expectedType;
            bool         typeNameSpecified = false;

            uri = null;

            if (jsonObjectTable.TryGetValue(XmlConstants.JsonMetadataString, out metadataObject))
            {
                metadataElementSpecified = true;
                JsonReader.JsonObjectRecords metadata = metadataObject as JsonReader.JsonObjectRecords;
                if (metadata == null)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidMetadataContent);
                }

                // Get the type information from the metadata object. if the type name is not specified,
                // then return the expectedType as the target type
                object objectTypeName;
                if (metadata.Entries.TryGetValue(XmlConstants.JsonTypeString, out objectTypeName))
                {
                    string typeName = objectTypeName as string;
                    if (string.IsNullOrEmpty(typeName))
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidTypeMetadata);
                    }

                    // Resolve resource type name
                    targetType = this.Service.Provider.TryResolveResourceType(typeName);
                    if (targetType == null || targetType.ResourceTypeKind == ResourceTypeKind.Primitive)
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeName(typeName));
                    }

                    if (expectedType != null && !expectedType.IsAssignableFrom(targetType))
                    {
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidTypeSpecified(typeName, expectedType.FullName));
                    }

                    typeNameSpecified = true;
                }

                uri = JsonDeserializer.ReadUri(metadata.Entries);
            }

            // Type information is optional for bind operations.
            // Top level operations cannot be bind operations, since uri need to have $links
            // for top level bind operations and that's a different code path.
            // For bind operations, uri must be specified and nothing else should be specified.
            bool bindOperation = !topLevel && uri != null && jsonObjectTable.Count == 1;

            // type name must be specified for POST or PUT/MERGE operations.
            if (!typeNameSpecified)
            {
                if (!bindOperation)
                {
                    if (expectedType == null)
                    {
                        // For open properties, you must specify the type information
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_MissingTypeInformationForOpenTypeProperties);
                    }
                    else if (this.Service.Provider.HasDerivedTypes(expectedType))
                    {
                        // For types that take part in inheritance, type information must be specified.
                        throw DataServiceException.CreateBadRequestError(Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance);
                    }
                }
                else
                {
                    // If the type name is not specified, we should set the type name to null, since in case of inheritance,
                    // we don't want to guess the type information.
                    targetType = null;
                }
            }

            return(targetType);
        }
        /// <summary>
        /// Creates a new <see cref="Deserializer"/> for the specified stream.
        /// </summary>
        /// <param name="description">description about the request uri.</param>
        /// <param name="dataService">Data service for which the deserializer will act.</param>
        /// <param name="update">indicates whether this is a update operation or not</param>
        /// <param name="tracker">Tracker to use for modifications.</param>
        /// <returns>A new instance of <see cref="Deserializer"/>.</returns>
        internal static Deserializer CreateDeserializer(RequestDescription description, IDataService dataService, bool update, UpdateTracker tracker)
        {
            string mimeType;
            System.Text.Encoding encoding;
            DataServiceHostWrapper host = dataService.OperationContext.Host;
            HttpProcessUtility.ReadContentType(host.RequestContentType, out mimeType, out encoding);
            ContentFormat requestFormat = WebUtil.SelectRequestFormat(mimeType, description);
            Stream requestStream = host.RequestStream;
            Debug.Assert(requestStream != null, "requestStream != null");
            Debug.Assert(tracker != null, "Change tracker must always be created.");
            Deserializer deserializer = null;

            Debug.Assert(
                (!update /*POST*/ && dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.POST) ||
                (update /*PUT,MERGE*/ && (dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.MERGE || dataService.OperationContext.Host.AstoriaHttpVerb == AstoriaVerbs.PUT)),
                "For PUT and MERGE, update must be true; for POST, update must be false");

            switch (requestFormat)
            {
                case ContentFormat.Json:
                    deserializer = new JsonDeserializer(
                        requestStream,
                        encoding,
                        update,
                        dataService,
                        tracker);
                    break;
                case ContentFormat.Atom:
                    SyndicationFormatterFactory factory = new Atom10FormatterFactory();
                    deserializer = new SyndicationDeserializer(
                        requestStream,  // stream
                        encoding,       // encoding
                        dataService,    // dataService
                        update,
                        factory,
                        tracker);       // factory
                    break;
                case ContentFormat.PlainXml:
                    deserializer = new PlainXmlDeserializer(
                        requestStream,
                        encoding,
                        dataService,
                        update,
                        tracker);
                    break;
                default:
                    throw new DataServiceException(415, Strings.BadRequest_UnsupportedRequestContentType(host.RequestContentType));
            }

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

            return deserializer;
        }