示例#1
0
        /// <summary>
        /// Appends the key expression for the given entity to the given <see cref="StringBuilder"/>
        /// </summary>
        /// <typeparam name="T">The type of the properties.</typeparam>
        /// <param name="keyProperties">The properties of the key.</param>
        /// <param name="getPropertyName">Delegate to get the name of a property.</param>
        /// <param name="getValueForProperty">Delegate to get the value of a property.</param>
        /// <param name="builder">The builder to append onto.</param>
        internal void AppendKeyExpression <T>(ICollection <T> keyProperties, Func <T, string> getPropertyName, Func <T, object> getValueForProperty, StringBuilder builder)
        {
            Func <T, object> getValueForPropertyWithNullCheck = p =>
            {
                Debug.Assert(getValueForProperty != null, "getValueForProperty != null");
                object propertyValue = getValueForProperty(p);
                if (propertyValue == null)
                {
                    throw Error.InvalidOperation(Client.Strings.Context_NullKeysAreNotSupported(getPropertyName(p)));
                }

                return(propertyValue);
            };

            this.keySerializer.AppendKeyExpression(builder, keyProperties, getPropertyName, getValueForPropertyWithNullCheck);
        }
示例#2
0
        /// <summary>
        /// Gets the raw CLR value for the given <see cref="IEdmPropertyValue"/>.
        /// </summary>
        /// <param name="property">The property to get the value for.</param>
        /// <param name="type">The type which declared the property.</param>
        /// <returns>The raw CLR value of the property.</returns>
        private static object GetPropertyValue(IEdmPropertyValue property, IEdmTypeReference type)
        {
            Debug.Assert(property != null, "property != null");
            IEdmValue propertyValue = property.Value;

            // DEVNOTE: though this check is not strictly necessary, and would be caught by later checks,
            // it seems worthwhile to fail fast if we can.
            if (propertyValue.ValueKind == EdmValueKind.Null)
            {
                throw Error.InvalidOperation(ErrorStrings.Context_NullKeysAreNotSupported(property.Name));
            }

            var primitiveValue = propertyValue as IEdmPrimitiveValue;

            if (primitiveValue == null)
            {
                throw Error.InvalidOperation(ErrorStrings.ClientType_KeysMustBeSimpleTypes(type.FullName()));
            }

            // DEVNOTE: This can return null, and will be handled later. The reason for this is that the client
            // and server have different ways of getting property values, but both will eventually hit the same
            // codepath and that is where the null is handled.
            return(primitiveValue.ToClrValue());
        }
示例#3
0
        /// <summary>
        /// discover and prepare properties for usage
        /// </summary>
        /// <param name="type">type being processed</param>
        /// <param name="typeName">parameter name</param>
        /// <param name="skipSettableCheck">Whether the skip the check for settable properties.</param>
        private ClientType(Type type, string typeName, bool skipSettableCheck)
        {
            Debug.Assert(null != type, "null type");
            Debug.Assert(!String.IsNullOrEmpty(typeName), "empty typeName");

            this.ElementTypeName = typeName;
            this.ElementType     = Nullable.GetUnderlyingType(type) ?? type;
#if ASTORIA_OPEN_OBJECT
            string openObjectPropertyName = null;
#endif
            if (!ClientConvert.IsKnownType(this.ElementType))
            {
#if ASTORIA_OPEN_OBJECT
                #region OpenObject determined by walking type hierarchy and looking for [OpenObjectAttribute("PropertyName")]
                Type openObjectDeclared = this.ElementType;
                for (Type tmp = openObjectDeclared; (null != tmp) && (typeof(object) != tmp); tmp = tmp.BaseType)
                {
                    object[] attributes = openObjectDeclared.GetCustomAttributes(typeof(OpenObjectAttribute), false);
                    if (1 == attributes.Length)
                    {
                        if (null != openObjectPropertyName)
                        {
                            throw Error.InvalidOperation(Strings.Clienttype_MultipleOpenProperty(this.ElementTypeName));
                        }

                        openObjectPropertyName = ((OpenObjectAttribute)attributes[0]).OpenObjectPropertyName;
                        openObjectDeclared     = tmp;
                    }
                }
                #endregion
#endif

                Type keyPropertyDeclaredType = null;
                bool isEntity = type.GetCustomAttributes(true).OfType <DataServiceEntityAttribute>().Any();
                DataServiceKeyAttribute dska = type.GetCustomAttributes(true).OfType <DataServiceKeyAttribute>().FirstOrDefault();
                foreach (PropertyInfo pinfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    //// examples where class<PropertyType>

                    //// the normal examples
                    //// PropertyType Property { get; set }
                    //// Nullable<PropertyType> Property { get; set; }

                    //// if 'Property: struct' then we would be unable set the property during construction (and have them stick)
                    //// but when its a class, we can navigate if non-null and set the nested properties
                    //// PropertyType Property { get; } where PropertyType: class

                    //// we do support adding elements to collections
                    //// ICollection<PropertyType> { get; /*ignored set;*/ }

                    //// indexed properties are not suported because
                    //// we don't have anything to use as the index
                    //// PropertyType Property[object x] { /*ignored get;*/ /*ignored set;*/ }

                    //// also ignored
                    //// if PropertyType.IsPointer (like byte*)
                    //// if PropertyType.IsArray except for byte[] and char[]
                    //// if PropertyType == IntPtr or UIntPtr

                    Type ptype = pinfo.PropertyType; // class / interface / value
                    ptype = Nullable.GetUnderlyingType(ptype) ?? ptype;

                    if (ptype.IsPointer ||
                        (ptype.IsArray && (typeof(byte[]) != ptype) && typeof(char[]) != ptype) ||
                        (typeof(IntPtr) == ptype) ||
                        (typeof(UIntPtr) == ptype))
                    {
                        continue;
                    }

                    Debug.Assert(!ptype.ContainsGenericParameters, "remove when test case is found that encounters this");

                    if (pinfo.CanRead &&
                        (!ptype.IsValueType || pinfo.CanWrite) &&
                        !ptype.ContainsGenericParameters &&
                        (0 == pinfo.GetIndexParameters().Length))
                    {
                        #region IsKey?
                        bool keyProperty = dska != null?dska.KeyNames.Contains(pinfo.Name) : false;

                        if (keyProperty)
                        {
                            if (null == keyPropertyDeclaredType)
                            {
                                keyPropertyDeclaredType = pinfo.DeclaringType;
                            }
                            else if (keyPropertyDeclaredType != pinfo.DeclaringType)
                            {
                                throw Error.InvalidOperation(Strings.ClientType_KeysOnDifferentDeclaredType(this.ElementTypeName));
                            }

                            if (!ClientConvert.IsKnownType(ptype))
                            {
                                throw Error.InvalidOperation(Strings.ClientType_KeysMustBeSimpleTypes(this.ElementTypeName));
                            }

                            this.KeyCount++;
                        }
                        #endregion

#if ASTORIA_OPEN_OBJECT
                        #region IsOpenObjectProperty?
                        bool openProperty = (openObjectPropertyName == pinfo.Name) &&
                                            typeof(IDictionary <string, object>).IsAssignableFrom(ptype);
                        Debug.Assert(keyProperty != openProperty || (!keyProperty && !openProperty), "key can't be open type");
                        #endregion

                        ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty, openProperty);

                        if (!property.OpenObjectProperty)
#else
                        ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty);
#endif
                        {
                            if (!this.properties.Add(property, ClientProperty.NameEquality))
                            {
                                // 2nd property with same name shadows another property
                                int shadow = this.IndexOfProperty(property.PropertyName);
                                if (!property.DeclaringType.IsAssignableFrom(this.properties[shadow].DeclaringType))
                                {   // the new property is on the most derived class
                                    this.properties.RemoveAt(shadow);
                                    this.properties.Add(property, null);
                                }
                            }
                        }
#if ASTORIA_OPEN_OBJECT
                        else
                        {
                            if (pinfo.DeclaringType == openObjectDeclared)
                            {
                                this.openProperties = property;
                            }
                        }
#endif
                    }
                }

                #region No KeyAttribute, discover key by name pattern { DeclaringType.Name+ID, ID }
                if (null == keyPropertyDeclaredType)
                {
                    ClientProperty key = null;
                    for (int i = this.properties.Count - 1; 0 <= i; --i)
                    {
                        string propertyName = this.properties[i].PropertyName;
                        if (propertyName.EndsWith("ID", StringComparison.Ordinal))
                        {
                            string declaringTypeName = this.properties[i].DeclaringType.Name;
                            if ((propertyName.Length == (declaringTypeName.Length + 2)) &&
                                propertyName.StartsWith(declaringTypeName, StringComparison.Ordinal))
                            {
                                // matched "DeclaringType.Name+ID" pattern
                                if ((null == keyPropertyDeclaredType) ||
                                    this.properties[i].DeclaringType.IsAssignableFrom(keyPropertyDeclaredType))
                                {
                                    keyPropertyDeclaredType = this.properties[i].DeclaringType;
                                    key = this.properties[i];
                                }
                            }
                            else if ((null == keyPropertyDeclaredType) && (2 == propertyName.Length))
                            {
                                // matched "ID" pattern
                                keyPropertyDeclaredType = this.properties[i].DeclaringType;
                                key = this.properties[i];
                            }
                        }
                    }

                    if (null != key)
                    {
                        Debug.Assert(0 == this.KeyCount, "shouldn't have a key yet");
                        key.KeyProperty = true;
                        this.KeyCount++;
                    }
                }
                else if (this.KeyCount != dska.KeyNames.Count)
                {
                    var m = (from string a in dska.KeyNames
                             where null == (from b in this.properties
                                            where b.PropertyName == a
                                            select b).FirstOrDefault()
                             select a).First <string>();
                    throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, m));
                }
                #endregion

                this.IsEntityType = (null != keyPropertyDeclaredType) || isEntity;
                Debug.Assert(this.KeyCount == this.Properties.Where(k => k.KeyProperty).Count(), "KeyCount mismatch");

                this.WireUpMimeTypeProperties();
                this.CheckMediaLinkEntry();

                if (!skipSettableCheck)
                {
#if ASTORIA_OPEN_OBJECT
                    if ((0 == this.properties.Count) && (null == this.openProperties))
#else
                    if (0 == this.properties.Count)
#endif
                    {   // implicit construction?
                        throw Error.InvalidOperation(Strings.ClientType_NoSettableFields(this.ElementTypeName));
                    }
                }
            }
示例#4
0
        private ClientType(Type type, string typeName, bool skipSettableCheck)
        {
            Debug.Assert(null != type, "null type");
            Debug.Assert(!String.IsNullOrEmpty(typeName), "empty typeName");

            this.ElementTypeName = typeName;
            this.ElementType     = Nullable.GetUnderlyingType(type) ?? type;
#if ASTORIA_OPEN_OBJECT
            string openObjectPropertyName = null;
#endif
            if (!ClientConvert.IsKnownType(this.ElementType))
            {
#if ASTORIA_OPEN_OBJECT
                #region OpenObject determined by walking type hierarchy and looking for [OpenObjectAttribute("PropertyName")]
                Type openObjectDeclared = this.ElementType;
                for (Type tmp = openObjectDeclared; (null != tmp) && (typeof(object) != tmp); tmp = tmp.BaseType)
                {
                    object[] attributes = openObjectDeclared.GetCustomAttributes(typeof(OpenObjectAttribute), false);
                    if (1 == attributes.Length)
                    {
                        if (null != openObjectPropertyName)
                        {
                            throw Error.InvalidOperation(Strings.Clienttype_MultipleOpenProperty(this.ElementTypeName));
                        }

                        openObjectPropertyName = ((OpenObjectAttribute)attributes[0]).OpenObjectPropertyName;
                        openObjectDeclared     = tmp;
                    }
                }
                #endregion
#endif

                Type keyPropertyDeclaredType = null;
                bool isEntity = type.GetCustomAttributes(true).OfType <DataServiceEntityAttribute>().Any();
                DataServiceKeyAttribute dska = type.GetCustomAttributes(true).OfType <DataServiceKeyAttribute>().FirstOrDefault();
                foreach (PropertyInfo pinfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    Type ptype = pinfo.PropertyType;
                    ptype = Nullable.GetUnderlyingType(ptype) ?? ptype;

                    if (ptype.IsPointer ||
                        (ptype.IsArray && (typeof(byte[]) != ptype) && typeof(char[]) != ptype) ||
                        (typeof(IntPtr) == ptype) ||
                        (typeof(UIntPtr) == ptype))
                    {
                        continue;
                    }

                    Debug.Assert(!ptype.ContainsGenericParameters, "remove when test case is found that encounters this");

                    if (pinfo.CanRead &&
                        (!ptype.IsValueType || pinfo.CanWrite) &&
                        !ptype.ContainsGenericParameters &&
                        (0 == pinfo.GetIndexParameters().Length))
                    {
                        #region IsKey?
                        bool keyProperty = dska != null?dska.KeyNames.Contains(pinfo.Name) : false;

                        if (keyProperty)
                        {
                            if (null == keyPropertyDeclaredType)
                            {
                                keyPropertyDeclaredType = pinfo.DeclaringType;
                            }
                            else if (keyPropertyDeclaredType != pinfo.DeclaringType)
                            {
                                throw Error.InvalidOperation(Strings.ClientType_KeysOnDifferentDeclaredType(this.ElementTypeName));
                            }

                            if (!ClientConvert.IsKnownType(ptype))
                            {
                                throw Error.InvalidOperation(Strings.ClientType_KeysMustBeSimpleTypes(this.ElementTypeName));
                            }

                            this.KeyCount++;
                        }
                        #endregion

#if ASTORIA_OPEN_OBJECT
                        #region IsOpenObjectProperty?
                        bool openProperty = (openObjectPropertyName == pinfo.Name) &&
                                            typeof(IDictionary <string, object>).IsAssignableFrom(ptype);
                        Debug.Assert(keyProperty != openProperty || (!keyProperty && !openProperty), "key can't be open type");
                        #endregion

                        ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty, openProperty);

                        if (!property.OpenObjectProperty)
#else
                        ClientProperty property = new ClientProperty(pinfo, ptype, keyProperty);
#endif
                        {
                            if (!this.properties.Add(property, ClientProperty.NameEquality))
                            {
                                int shadow = this.IndexOfProperty(property.PropertyName);
                                if (!property.DeclaringType.IsAssignableFrom(this.properties[shadow].DeclaringType))
                                {
                                    this.properties.RemoveAt(shadow);
                                    this.properties.Add(property, null);
                                }
                            }
                        }
#if ASTORIA_OPEN_OBJECT
                        else
                        {
                            if (pinfo.DeclaringType == openObjectDeclared)
                            {
                                this.openProperties = property;
                            }
                        }
#endif
                    }
                }

                #region No KeyAttribute, discover key by name pattern { DeclaringType.Name+ID, ID }
                if (null == keyPropertyDeclaredType)
                {
                    ClientProperty key = null;
                    for (int i = this.properties.Count - 1; 0 <= i; --i)
                    {
                        string propertyName = this.properties[i].PropertyName;
                        if (propertyName.EndsWith("ID", StringComparison.Ordinal))
                        {
                            string declaringTypeName = this.properties[i].DeclaringType.Name;
                            if ((propertyName.Length == (declaringTypeName.Length + 2)) &&
                                propertyName.StartsWith(declaringTypeName, StringComparison.Ordinal))
                            {
                                if ((null == keyPropertyDeclaredType) ||
                                    this.properties[i].DeclaringType.IsAssignableFrom(keyPropertyDeclaredType))
                                {
                                    keyPropertyDeclaredType = this.properties[i].DeclaringType;
                                    key = this.properties[i];
                                }
                            }
                            else if ((null == keyPropertyDeclaredType) && (2 == propertyName.Length))
                            {
                                keyPropertyDeclaredType = this.properties[i].DeclaringType;
                                key = this.properties[i];
                            }
                        }
                    }

                    if (null != key)
                    {
                        Debug.Assert(0 == this.KeyCount, "shouldn't have a key yet");
                        key.KeyProperty = true;
                        this.KeyCount++;
                    }
                }
                else if (this.KeyCount != dska.KeyNames.Count)
                {
                    var m = (from string a in dska.KeyNames
                             where null == (from b in this.properties
                                            where b.PropertyName == a
                                            select b).FirstOrDefault()
                             select a).First <string>();
                    throw Error.InvalidOperation(Strings.ClientType_MissingProperty(this.ElementTypeName, m));
                }
                #endregion

                this.IsEntityType = (null != keyPropertyDeclaredType) || isEntity;
                Debug.Assert(this.KeyCount == this.Properties.Where(k => k.KeyProperty).Count(), "KeyCount mismatch");

                this.WireUpMimeTypeProperties();
                this.CheckMediaLinkEntry();

                if (!skipSettableCheck)
                {
#if ASTORIA_OPEN_OBJECT
                    if ((0 == this.properties.Count) && (null == this.openProperties))
#else
                    if (0 == this.properties.Count)
#endif
                    {
                        throw Error.InvalidOperation(Strings.ClientType_NoSettableFields(this.ElementTypeName));
                    }
                }
            }
示例#5
0
        private string ConvertToEscapedUriValue(string paramName, object value)
        {
            Debug.Assert(!string.IsNullOrEmpty(paramName), "!string.IsNullOrEmpty(paramName)");
            Object valueInODataFormat = null;

            // Literal values with single quotes need special escaping due to System.Uri changes in behavior between .NET 4.0 and 4.5.
            // We need to ensure that our escaped values do not change between those versions, so we need to escape values differently when they could contain single quotes.
            bool needsSpecialEscaping = false;

            if (value == null)
            {
                needsSpecialEscaping = true;
            }
            else
            {
                if (value.GetType() == typeof(ODataUriNullValue))
                {
                    valueInODataFormat   = value;
                    needsSpecialEscaping = true;
                }
                else
                {
                    ClientEdmModel model   = this.requestInfo.Model;
                    IEdmType       edmType = model.GetOrCreateEdmType(value.GetType());
                    Debug.Assert(edmType != null, "edmType != null");

                    switch (edmType.TypeKind)
                    {
                    case EdmTypeKind.Primitive:
                        valueInODataFormat   = value;
                        needsSpecialEscaping = true;
                        break;

                    case EdmTypeKind.Complex:
                        ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType);
                        Debug.Assert(typeAnnotation != null, "typeAnnotation != null");
                        valueInODataFormat = this.propertyConverter.CreateODataComplexValue(
                            typeAnnotation.ElementType,
                            value,
                            null /*propertyName*/,
                            false /*isCollectionItemType*/,
                            null /*visitedComplexTypeObjects*/);

                        // When using JsonVerbose to format query string parameters for Actions,
                        // we cannot write out Complex values in the URI without the type name of the complex type in the JSON payload.
                        // If this value is null, the client has to set the ResolveName property on the DataServiceContext instance.
                        ODataComplexValue complexValue = (ODataComplexValue)valueInODataFormat;
                        SerializationTypeNameAnnotation serializedTypeNameAnnotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>();
                        if (serializedTypeNameAnnotation == null || string.IsNullOrEmpty(serializedTypeNameAnnotation.TypeName))
                        {
                            throw Error.InvalidOperation(Strings.DataServiceException_GeneralError);
                        }

                        break;

                    case EdmTypeKind.Collection:
                        IEdmCollectionType edmCollectionType = edmType as IEdmCollectionType;
                        Debug.Assert(edmCollectionType != null, "edmCollectionType != null");
                        IEdmTypeReference itemTypeReference = edmCollectionType.ElementType;
                        Debug.Assert(itemTypeReference != null, "itemTypeReference != null");
                        ClientTypeAnnotation itemTypeAnnotation = model.GetClientTypeAnnotation(itemTypeReference.Definition);
                        Debug.Assert(itemTypeAnnotation != null, "itemTypeAnnotation != null");

                        switch (itemTypeAnnotation.EdmType.TypeKind)
                        {
                        // We only support primitive or complex type as a collection item type.
                        case EdmTypeKind.Primitive:
                        case EdmTypeKind.Complex:
                            break;

                        default:
                            throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(paramName, itemTypeAnnotation.EdmType.TypeKind));
                        }

                        valueInODataFormat = this.propertyConverter.CreateODataCollection(
                            itemTypeAnnotation.ElementType,
                            null /*propertyName*/,
                            value,
                            null /*visitedComplexTypeObjects*/);
                        break;

                    default:
                        // EdmTypeKind.Entity
                        // EdmTypeKind.Row
                        // EdmTypeKind.EntityReference
                        // EdmTypeKind.Enum.
                        throw new NotSupportedException(Strings.Serializer_InvalidParameterType(paramName, edmType.TypeKind));
                    }
                }

                Debug.Assert(valueInODataFormat != null, "valueInODataFormat != null");
            }

            // In the released WCF Data Services 5.0, we didn't pass the model for JSON Verbose literals, so continuing that behavior for backward compatibility
            ODataFormat literalFormat = this.requestInfo.Format.UriLiteralFormat;
            IEdmModel   edmModel      = literalFormat == ODataFormat.VerboseJson ? null : this.requestInfo.Model;

            // ODL can handle null values so we can send null values here.
            string literal = ODataUriUtils.ConvertToUriLiteral(valueInODataFormat, CommonUtil.ConvertToODataVersion(this.requestInfo.MaxProtocolVersionAsVersion), edmModel, literalFormat);

            // The value from ConvertToUriValue will not be escaped, but will already contain literal delimiters like single quotes, so we
            // need to use our own escape method that will preserve those characters instead of directly calling Uri.EscapeDataString that may escape them.
            // This is only necessary for primitives and nulls because the other structures are serialized using the JSON format and it uses double quotes
            // which have always been escaped.
            if (needsSpecialEscaping)
            {
                return(DataStringEscapeBuilder.EscapeDataString(literal));
            }

            return(Uri.EscapeDataString(literal));
        }
示例#6
0
        /// <summary>
        /// Parses the current reader into a new <paramref name="targetEntry"/>
        /// instance.
        /// </summary>
        /// <param name="targetEntry">
        /// After invocation, the target entry that was created as a result
        /// of parsing the current reader.
        /// </param>
        private void ParseCurrentEntry(out AtomEntry targetEntry)
        {
            Debug.Assert(this.reader.NodeType == XmlNodeType.Element, "this.reader.NodeType == XmlNodeType.Element");

            // Push reader.
            var callbackResult = this.entryCallback(this.reader);

            Debug.Assert(callbackResult.Key != null, "callbackResult.Key != null");
            this.readers.Push(this.reader);
            this.reader = callbackResult.Key;

            this.reader.Read();
            Debug.Assert(this.reader.LocalName == "entry", "this.reader.LocalName == 'entry' - otherwise we're not reading the subtree");

            bool hasContent = false;

            targetEntry            = new AtomEntry();
            targetEntry.DataValues = new List <AtomContentProperty>();
            targetEntry.Tag        = callbackResult.Value;
            targetEntry.ETagText   = this.reader.GetAttribute(XmlConstants.AtomETagAttributeName, XmlConstants.DataWebMetadataNamespace);

            while (this.reader.Read())
            {
                if (ShouldIgnoreNode(this.reader))
                {
                    continue;
                }

                if (this.reader.NodeType == XmlNodeType.Element)
                {
                    int    depth        = this.reader.Depth;
                    string elementName  = this.reader.LocalName;
                    string namespaceURI = this.reader.NamespaceURI;
                    if (namespaceURI == XmlConstants.AtomNamespace)
                    {
                        if (elementName == XmlConstants.AtomCategoryElementName && targetEntry.TypeName == null)
                        {
                            string text = this.reader.GetAttributeEx(XmlConstants.AtomCategorySchemeAttributeName, XmlConstants.AtomNamespace);
                            if (text == this.typeScheme)
                            {
                                targetEntry.TypeName = this.reader.GetAttributeEx(XmlConstants.AtomCategoryTermAttributeName, XmlConstants.AtomNamespace);
                            }
                        }
                        else if (elementName == XmlConstants.AtomContentElementName)
                        {
                            hasContent = true;
                            this.ParseCurrentContent(targetEntry);
                        }
                        else if (elementName == XmlConstants.AtomIdElementName && targetEntry.Identity == null)
                        {
                            // The .Identity == null check ensures that only the first id element is processed.
                            string idText = ReadElementStringForText(this.reader);
                            idText = Util.ReferenceIdentity(idText);

                            // here we could just assign idText to Identity
                            // however we used to check for AbsoluteUri, thus we need to
                            // convert string to Uri and check for absoluteness
                            Uri idUri = Util.CreateUri(idText, UriKind.RelativeOrAbsolute);
                            if (!idUri.IsAbsoluteUri)
                            {
                                throw Error.InvalidOperation(Strings.Context_TrackingExpectsAbsoluteUri);
                            }

                            targetEntry.Identity = idText;
                        }
                        else if (elementName == XmlConstants.AtomLinkElementName)
                        {
                            this.ParseCurrentLink(targetEntry);
                        }
                    }
                    else if (namespaceURI == XmlConstants.DataWebMetadataNamespace)
                    {
                        if (elementName == XmlConstants.AtomPropertiesElementName)
                        {
                            if (targetEntry.MediaLinkEntry.HasValue && !targetEntry.MediaLinkEntry.Value)
                            {
                                // This means we saw a non-empty <atom:Content> element but now we have a Properties element
                                // that also carries properties
                                throw Error.InvalidOperation(Strings.Deserialize_ContentPlusPropertiesNotAllowed);
                            }

                            targetEntry.MediaLinkEntry = true;

                            if (!this.reader.IsEmptyElement)
                            {
                                this.ReadCurrentProperties(targetEntry.DataValues);
                            }
                        }
                    }

                    SkipToEndAtDepth(this.reader, depth);
                }
            }

            if (targetEntry.Identity == null)
            {
                throw Error.InvalidOperation(Strings.Deserialize_MissingIdElement);
            }

            if (!hasContent)
            {
                // Content is expected for the GetResponse operation
                throw Error.BatchStreamContentExpected(BatchStreamState.GetResponse);
            }

            this.reader = this.readers.Pop();
        }
示例#7
0
        private void ParseCurrentLink(AtomEntry targetEntry)
        {
            Debug.Assert(targetEntry != null, "targetEntry != null");
            Debug.Assert(
                this.reader.NodeType == XmlNodeType.Element,
                "this.reader.NodeType == XmlNodeType.Element -- otherwise we shouldn't try to parse a link");
            Debug.Assert(
                this.reader.LocalName == "link",
                "this.reader.LocalName == 'link' -- otherwise we shouldn't try to parse a link");

            string relation = this.reader.GetAttribute(XmlConstants.AtomLinkRelationAttributeName);

            if (relation == null)
            {
                return;
            }

            if (relation == XmlConstants.AtomEditRelationAttributeValue && targetEntry.EditLink == null)
            {
                // Only process the first link that has @rel='edit'.
                string href = this.reader.GetAttribute(XmlConstants.AtomHRefAttributeName);
                if (String.IsNullOrEmpty(href))
                {
                    throw Error.InvalidOperation(Strings.Context_MissingEditLinkInResponseBody);
                }

                targetEntry.EditLink = this.ConvertHRefAttributeValueIntoURI(href);
            }
            else if (relation == XmlConstants.AtomSelfRelationAttributeValue && targetEntry.QueryLink == null)
            {
                // Only process the first link that has @rel='self'.
                string href = this.reader.GetAttribute(XmlConstants.AtomHRefAttributeName);
                if (String.IsNullOrEmpty(href))
                {
                    throw Error.InvalidOperation(Strings.Context_MissingSelfLinkInResponseBody);
                }

                targetEntry.QueryLink = this.ConvertHRefAttributeValueIntoURI(href);
            }
            else if (relation == XmlConstants.AtomEditMediaRelationAttributeValue && targetEntry.MediaEditUri == null)
            {
                string href = this.reader.GetAttribute(XmlConstants.AtomHRefAttributeName);
                if (String.IsNullOrEmpty(href))
                {
                    throw Error.InvalidOperation(Strings.Context_MissingEditMediaLinkInResponseBody);
                }

                targetEntry.MediaEditUri   = this.ConvertHRefAttributeValueIntoURI(href);
                targetEntry.StreamETagText = this.reader.GetAttribute(XmlConstants.AtomETagAttributeName, XmlConstants.DataWebMetadataNamespace);
            }

            if (!this.reader.IsEmptyElement)
            {
                string propertyName = UriUtil.GetNameFromAtomLinkRelationAttribute(relation);
                if (propertyName == null)
                {
                    return;
                }

                string propertyValueText = this.reader.GetAttribute(XmlConstants.AtomTypeAttributeName);
                bool   isFeed;

                if (!IsAllowedLinkType(propertyValueText, out isFeed))
                {
                    return;
                }

                if (!ReadChildElement(this.reader, XmlConstants.AtomInlineElementName, XmlConstants.DataWebMetadataNamespace))
                {
                    return;
                }

                bool   emptyInlineCollection = this.reader.IsEmptyElement;
                object propertyValue         = null;

                if (!emptyInlineCollection)
                {
                    AtomFeed         nestedFeed  = null;
                    AtomEntry        nestedEntry = null;
                    List <AtomEntry> feedEntries = null;

                    Debug.Assert(this.reader is Xml.XmlWrappingReader, "reader must be a instance of XmlWrappingReader");
                    string    readerBaseUri = this.reader.BaseURI;
                    XmlReader nestedReader  = Xml.XmlWrappingReader.CreateReader(readerBaseUri, this.reader.ReadSubtree());
                    nestedReader.Read();
                    Debug.Assert(nestedReader.LocalName == "inline", "nestedReader.LocalName == 'inline'");

                    AtomParser nested = new AtomParser(nestedReader, this.entryCallback, this.typeScheme, this.currentDataNamespace);
                    while (nested.Read())
                    {
                        switch (nested.DataKind)
                        {
                        case AtomDataKind.Feed:
                            feedEntries   = new List <AtomEntry>();
                            nestedFeed    = nested.CurrentFeed;
                            propertyValue = nestedFeed;
                            break;

                        case AtomDataKind.Entry:
                            nestedEntry = nested.CurrentEntry;
                            if (feedEntries != null)
                            {
                                feedEntries.Add(nestedEntry);
                            }
                            else
                            {
                                propertyValue = nestedEntry;
                            }

                            break;

                        case AtomDataKind.PagingLinks:
                            // Here the inner feed parser found a paging link, and stored it on nestedFeed.NextPageLink
                            // we are going to add it into a link table and associate
                            // with the collection at AtomMaterializer::Materialize()
                            // Do nothing for now.
                            break;

                        default:
                            throw new InvalidOperationException(Strings.AtomParser_UnexpectedContentUnderExpandedLink);
                        }
                    }

                    if (nestedFeed != null)
                    {
                        Debug.Assert(
                            nestedFeed.Entries == null,
                            "nestedFeed.Entries == null -- otherwise someone initialized this for us");
                        nestedFeed.Entries = feedEntries;
                    }
                }

                AtomContentProperty property = new AtomContentProperty();
                property.Name = propertyName;

                if (emptyInlineCollection || propertyValue == null)
                {
                    property.IsNull = true;
                    if (isFeed)
                    {
                        property.Feed         = new AtomFeed();
                        property.Feed.Entries = Enumerable.Empty <AtomEntry>();
                    }
                    else
                    {
                        property.Entry        = new AtomEntry();
                        property.Entry.IsNull = true;
                    }
                }
                else
                {
                    property.Feed  = propertyValue as AtomFeed;
                    property.Entry = propertyValue as AtomEntry;
                }

                targetEntry.DataValues.Add(property);
            }
        }
示例#8
0
        internal static object ChangeType(string propertyValue, Type propertyType)
        {
            Debug.Assert(null != propertyValue, "should never be passed null");
            try
            {
                switch ((StorageType)IndexOfStorage(propertyType))
                {
                case StorageType.Boolean:
                    return(XmlConvert.ToBoolean(propertyValue));

                case StorageType.Byte:
                    return(XmlConvert.ToByte(propertyValue));

                case StorageType.ByteArray:
                    return(Convert.FromBase64String(propertyValue));

                case StorageType.Char:
                    return(XmlConvert.ToChar(propertyValue));

                case StorageType.CharArray:
                    return(propertyValue.ToCharArray());

                case StorageType.DateTime:
                    return(XmlConvert.ToDateTime(propertyValue, XmlDateTimeSerializationMode.RoundtripKind));

                case StorageType.DateTimeOffset:
                    return(XmlConvert.ToDateTimeOffset(propertyValue));

                case StorageType.Decimal:
                    return(XmlConvert.ToDecimal(propertyValue));

                case StorageType.Double:
                    return(XmlConvert.ToDouble(propertyValue));

                case StorageType.Guid:
                    return(new Guid(propertyValue));

                case StorageType.Int16:
                    return(XmlConvert.ToInt16(propertyValue));

                case StorageType.Int32:
                    return(XmlConvert.ToInt32(propertyValue));

                case StorageType.Int64:
                    return(XmlConvert.ToInt64(propertyValue));

                case StorageType.Single:
                    return(XmlConvert.ToSingle(propertyValue));

                case StorageType.String:
                    return(propertyValue);

                case StorageType.SByte:
                    return(XmlConvert.ToSByte(propertyValue));

                case StorageType.TimeSpan:
                    return(XmlConvert.ToTimeSpan(propertyValue));

                case StorageType.Type:
                    return(Type.GetType(propertyValue, true));

                case StorageType.UInt16:
                    return(XmlConvert.ToUInt16(propertyValue));

                case StorageType.UInt32:
                    return(XmlConvert.ToUInt32(propertyValue));

                case StorageType.UInt64:
                    return(XmlConvert.ToUInt64(propertyValue));

                case StorageType.Uri:
                    return(Util.CreateUri(propertyValue, UriKind.RelativeOrAbsolute));

                case StorageType.XDocument:
                    return(0 < propertyValue.Length ? System.Xml.Linq.XDocument.Parse(propertyValue) : new System.Xml.Linq.XDocument());

                case StorageType.XElement:
                    return(System.Xml.Linq.XElement.Parse(propertyValue));

#if !ASTORIA_LIGHT
                case StorageType.Binary:
                    Debug.Assert(null != knownTypes[(int)StorageType.Binary], "null typeof(System.Data.Linq.Binary)");
                    return(Activator.CreateInstance(knownTypes[(int)StorageType.Binary], Convert.FromBase64String(propertyValue)));
#endif
                default:
                    Debug.Assert(false, "new StorageType without update to knownTypes");
                    return(propertyValue);
                }
            }
            catch (FormatException ex)
            {
                propertyValue = (0 == propertyValue.Length ? "String.Empty" : "String");
                throw Error.InvalidOperation(Strings.Deserialize_Current(propertyType.ToString(), propertyValue), ex);
            }
            catch (OverflowException ex)
            {
                propertyValue = (0 == propertyValue.Length ? "String.Empty" : "String");
                throw Error.InvalidOperation(Strings.Deserialize_Current(propertyType.ToString(), propertyValue), ex);
            }
        }