Пример #1
0
        /// <summary>
        /// Returns true if the payload is correct for the top level non-entity target.
        /// </summary>
        /// <param name="jsonObject">json object representing the data in the payload.</param>
        /// <param name="segment">information about the last segment in the request uri.</param>
        /// <param name="resource">resource object as specified in the payload.</param>
        /// <returns>returns true if the payload is correct for non-entity resource.</returns>
        private static bool HandleTopLevelNonEntityProperty(JsonReader.JsonObjectRecords jsonObject, SegmentInfo segment, out object resource)
        {
            Debug.Assert(jsonObject != null, "jsonObject != null");
            Debug.Assert(segment != null, "segment != null");
            resource = null;

            if (segment.TargetKind == RequestTargetKind.Primitive ||
                segment.TargetKind == RequestTargetKind.OpenProperty ||
                segment.TargetKind == RequestTargetKind.ComplexObject)
            {
                if (jsonObject.Count == 1 && jsonObject.Entries.TryGetValue(segment.Identifier, out resource))
                {
                    // For open property, assume it to be a primitive or complex payload.
                    // If its targeting an entity, then the type must be specified
                    return(true);
                }
                else if (segment.TargetKind != RequestTargetKind.OpenProperty)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
                }
            }

            // its an entity resource payload
            return(false);
        }
Пример #2
0
        /// <summary>
        /// Verifies if the given element value is a deferred element or not
        /// </summary>
        /// <param name="element">element value</param>
        /// <returns>true if this value is a deferred content else returns false</returns>
        private static bool IsDeferredElement(object element)
        {
            JsonReader.JsonObjectRecords records = element as JsonReader.JsonObjectRecords;

            if (records != null && records.Count == 1 && records.OrderedKeys[0] == XmlConstants.JsonDeferredString)
            {
                return(true);
            }

            return(false);
        }
Пример #3
0
        /// <summary>
        /// Get the resource referred by the uri in the payload
        /// </summary>
        /// <returns>resource referred by the uri in the payload.</returns>
        protected override string GetLinkUriFromPayload()
        {
            // top level json content must be JsonObjectRecords, since we don't allow multiple inserts
            // at the top level
            JsonReader.JsonObjectRecords jsonObject = this.jsonReader.ReadValue() as JsonReader.JsonObjectRecords;
            if (jsonObject == null)
            {
                throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
            }

            string uri = ReadUri(jsonObject.Entries);

            if (String.IsNullOrEmpty(uri))
            {
                throw DataServiceException.CreateBadRequestError(Strings.BadRequest_MissingUriForLinkOperation);
            }

            return(uri);
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
        /// <summary>
        /// Populate the properties of the given resource
        /// </summary>
        /// <param name="jsonObject">JsonObjectRecords containing property name and values</param>
        /// <param name="resource">instance of the resource whose properties needs to be populated</param>
        /// <param name="parentResourceSet">resource set where <paramref name="resource"/> belongs to</param>
        /// <param name="parentResourceType">resource type whose properties needs to be populated</param>
        /// <returns>true if any properties were set; false otherwise.</returns>
        private bool PopulateProperties(JsonReader.JsonObjectRecords jsonObject, object resource, ResourceSetWrapper parentResourceSet, ResourceType parentResourceType)
        {
            // Update all the properties specified in the payload.
            // Don't touch the properties which are not specified. Its upto the provider to interpret
            // the meaning of things which are not specified
            bool changed = false;
            List <ResourceProperty> navProperties     = new List <ResourceProperty>();
            List <object>           navPropertyValues = new List <object>();

            #region Handle Non-Nav Properties
            foreach (string propertyName in jsonObject.OrderedKeys)
            {
                // Ignore the metadata property
                if (propertyName == XmlConstants.JsonMetadataString)
                {
                    continue;
                }

                // Check if the property exists and try and set the value
                ResourceProperty resourceProperty = parentResourceType.TryResolvePropertyName(propertyName);
                if (resourceProperty == null && parentResourceType.IsOpenType == false)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
                }

                // Get the property value, set it appropriately, and mark the object as changed.
                object propertyValue = jsonObject.Entries[propertyName];
                bool   existingRelationship;

                // If its a open property
                if (resourceProperty == null)
                {
                    this.HandleOpenTypeProperties(resource, propertyName, propertyValue);
                    changed = true;
                }
                else if (resourceProperty.TypeKind == ResourceTypeKind.ComplexType)
                {
                    SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, null, true /* singleResult */);
                    segmentInfo.TargetKind = RequestTargetKind.ComplexObject;
                    propertyValue          = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
                    SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service);
                    changed = true;
                }
                else if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
                {
                    // Ignoring the value of key properties in PUT payload
                    if (!this.Update || !resourceProperty.IsOfKind(ResourcePropertyKind.Key))
                    {
                        SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service);
                    }

                    changed = true;
                }
                else
                {
                    Debug.Assert(ResourceTypeKind.EntityType == resourceProperty.TypeKind, "only expecting nav properties");

                    if (IsDeferredElement(propertyValue))
                    {
                        // Skip the deferred element
                        continue;
                    }
                    else
                    {
                        navProperties.Add(resourceProperty);
                        navPropertyValues.Add(propertyValue);
                    }
                }
            }

            #endregion Non-Navigation Properties

            #region Handle Navigation Properties

            Debug.Assert(navProperties.Count == navPropertyValues.Count, "nav properties and nav property values count must be the same");

            // The reason why we need to do this is so that we can gaurantee that the nav properties are getting set at the end.
            // This is nice, since we already do this in the atom deserializer. Hence its consistent. Second, we wanted to
            // give a gaurantee that when FK and nav properties are specified in the payload, nav properties always win.
            for (int i = 0; i < navProperties.Count; i++)
            {
                this.HandleNavigationProperty(parentResourceSet, parentResourceType, resource, navProperties[i], navPropertyValues[i]);
                changed = true;
            }

            #endregion Handle Navigation Properties

            return(changed);
        }