Beispiel #1
0
        /// <summary>
        /// Implementation of Read>.
        /// </summary>
        /// <returns>
        /// Return value of Read/>
        /// </returns>
        protected sealed override bool ReadImplementation()
        {
            if (!this.hasReadValue)
            {
                try
                {
                    ClientEdmModel    model              = this.MaterializerContext.Model;
                    Type              expectedType       = this.ExpectedType;
                    IEdmTypeReference expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(ClientTypeUtil.CanAssignNull(expectedType));
                    if ((this.SingleResult.HasValue && !this.SingleResult.Value) && expectedClientType.Definition.TypeKind != EdmTypeKind.Collection)
                    {
                        expectedType = typeof(ICollection <>).MakeGenericType(expectedType);

                        // we do not allow null values for collection
                        expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(false);
                    }

                    IEdmTypeReference expectedReaderType = this.MaterializerContext.ResolveExpectedTypeForReading(expectedType).ToEdmTypeReference(expectedClientType.IsNullable);

                    this.ReadWithExpectedType(expectedClientType, expectedReaderType);
                }
                catch (ODataErrorException e)
                {
                    throw new DataServiceClientException(ClientStrings.Deserialize_ServerException(e.Error.Message), e);
                }
                catch (ODataException e)
                {
                    throw new InvalidOperationException(e.Message, e);
                }
                catch (ArgumentException e)
                {
                    throw new InvalidOperationException(e.Message, e);
                }
                finally
                {
                    this.hasReadValue = true;
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }
Beispiel #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());
        }
        public bool AddCollection(
            object source,
            string sourceProperty,
            object collection,
            string collectionEntitySet)
        {
            Debug.Assert(collection != null, "'collection' can not be null");
            Debug.Assert(
                BindingEntityInfo.IsDataServiceCollection(collection.GetType()),
                "Argument 'collection' must be an DataServiceCollection<T> of entity type T");

            if (this.graph.ExistsVertex(collection))
            {
                return(false);
            }

            Vertex collectionVertex = this.graph.AddVertex(collection);

            collectionVertex.IsCollection = true;
            collectionVertex.EntitySet    = collectionEntitySet;

            ICollection collectionItf = collection as ICollection;

            if (source != null)
            {
                collectionVertex.Parent         = this.graph.LookupVertex(source);
                collectionVertex.ParentProperty = sourceProperty;
                this.graph.AddEdge(source, collection, sourceProperty);

                Type entityType = BindingUtils.GetCollectionEntityType(collection.GetType());
                Debug.Assert(entityType != null, "Collection must at least be inherited from DataServiceCollection<T>");

                if (!typeof(INotifyPropertyChanged).IsAssignableFrom(entityType))
                {
                    throw new InvalidOperationException(Strings.DataBinding_NotifyPropertyChangedNotImpl(entityType));
                }

                typeof(BindingGraph)
                .GetMethod("SetObserver", BindingFlags.Instance | BindingFlags.NonPublic)
                .MakeGenericMethod(entityType)
                .Invoke(this, new object[] { collectionItf });
            }
            else
            {
                this.graph.Root = collectionVertex;
            }

            Debug.Assert(
                collectionVertex.Parent != null || collectionVertex.IsRootCollection,
                "If parent is null, then collectionVertex should be a root collection");

            this.AttachCollectionNotification(collection);

            foreach (var item in collectionItf)
            {
                this.AddEntity(
                    source,
                    sourceProperty,
                    item,
                    collectionEntitySet,
                    collection);
            }

            return(true);
        }
        public bool AddEntity(
            object source,
            string sourceProperty,
            object target,
            string targetEntitySet,
            object edgeSource)
        {
            Vertex sourceVertex = this.graph.LookupVertex(edgeSource);

            Debug.Assert(sourceVertex != null, "Must have a valid edge source");

            Vertex entityVertex   = null;
            bool   addedNewEntity = false;

            if (target != null)
            {
                entityVertex = this.graph.LookupVertex(target);

                if (entityVertex == null)
                {
                    entityVertex = this.graph.AddVertex(target);

                    entityVertex.EntitySet = BindingEntityInfo.GetEntitySet(target, targetEntitySet);

                    if (!this.AttachEntityOrComplexObjectNotification(target))
                    {
                        throw new InvalidOperationException(Strings.DataBinding_NotifyPropertyChangedNotImpl(target.GetType()));
                    }

                    addedNewEntity = true;
                }

                if (this.graph.ExistsEdge(edgeSource, target, sourceVertex.IsCollection ? null : sourceProperty))
                {
                    throw new InvalidOperationException(Strings.DataBinding_EntityAlreadyInCollection(target.GetType()));
                }

                this.graph.AddEdge(edgeSource, target, sourceVertex.IsCollection ? null : sourceProperty);
            }

            if (!sourceVertex.IsCollection)
            {
                this.observer.HandleUpdateEntityReference(
                    source,
                    sourceProperty,
                    sourceVertex.EntitySet,
                    target,
                    entityVertex == null ? null : entityVertex.EntitySet);
            }
            else
            {
                Debug.Assert(target != null, "Target must be non-null when adding to collections");
                this.observer.HandleAddEntity(
                    source,
                    sourceProperty,
                    sourceVertex.Parent != null ? sourceVertex.Parent.EntitySet : null,
                    edgeSource as ICollection,
                    target,
                    entityVertex.EntitySet);
            }

            if (addedNewEntity)
            {
                this.AddFromProperties(target);
            }

            return(addedNewEntity);
        }
Beispiel #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));
        }
Beispiel #6
0
        /// <summary>
        /// Writes the body operation parameters associated with a ServiceAction.
        /// </summary>
        /// <param name="operationParameters">The list of operation parameters to write.</param>
        /// <param name="requestMessage">The OData request message used to write the operation parameters.</param>
        internal void WriteBodyOperationParameters(List <BodyOperationParameter> operationParameters, ODataRequestMessageWrapper requestMessage)
        {
            Debug.Assert(requestMessage != null, "requestMessage != null");
            Debug.Assert(operationParameters != null, "operationParameters != null");
            Debug.Assert(operationParameters.Any(), "operationParameters.Any()");

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, true /*isParameterPayload*/))
            {
                ODataParameterWriter parameterWriter = messageWriter.CreateODataParameterWriter(null);
                parameterWriter.WriteStart();

                foreach (OperationParameter operationParameter in operationParameters)
                {
                    if (operationParameter.Value == null)
                    {
                        parameterWriter.WriteValue(operationParameter.Name, operationParameter.Value);
                    }
                    else
                    {
                        ClientEdmModel model   = this.requestInfo.Model;
                        IEdmType       edmType = model.GetOrCreateEdmType(operationParameter.Value.GetType());
                        Debug.Assert(edmType != null, "edmType != null");

                        switch (edmType.TypeKind)
                        {
                        case EdmTypeKind.Collection:
                        {
                            Collections.IEnumerator enumerator           = ((ICollection)operationParameter.Value).GetEnumerator();
                            ODataCollectionWriter   collectionWriter     = parameterWriter.CreateCollectionWriter(operationParameter.Name);
                            ODataCollectionStart    odataCollectionStart = new ODataCollectionStart();
                            collectionWriter.WriteStart(odataCollectionStart);

                            while (enumerator.MoveNext())
                            {
                                Object collectionItem = enumerator.Current;
                                if (collectionItem == null)
                                {
                                    throw new NotSupportedException(Strings.Serializer_NullCollectionParamterItemValue(operationParameter.Name));
                                }

                                IEdmType edmItemType = model.GetOrCreateEdmType(collectionItem.GetType());
                                Debug.Assert(edmItemType != null, "edmItemType != null");

                                switch (edmItemType.TypeKind)
                                {
                                case EdmTypeKind.Complex:
                                {
                                    Debug.Assert(model.GetClientTypeAnnotation(edmItemType).ElementType != null, "edmItemType.GetClientTypeAnnotation().ElementType != null");
                                    ODataComplexValue complexValue = this.propertyConverter.CreateODataComplexValue(
                                        model.GetClientTypeAnnotation(edmItemType).ElementType,
                                        collectionItem,
                                        null /*propertyName*/,
                                        false /*isCollectionItem*/,
                                        null /*visitedComplexTypeObjects*/);

                                    Debug.Assert(complexValue != null, "complexValue != null");
                                    collectionWriter.WriteItem(complexValue);
                                    break;
                                }

                                case EdmTypeKind.Primitive:
                                {
                                    collectionWriter.WriteItem(collectionItem);
                                    break;
                                }

                                default:

                                    // EdmTypeKind.Entity
                                    // EdmTypeKind.Row
                                    // EdmTypeKind.EntityReference
                                    // EdmTypeKind.Enum.
                                    throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(operationParameter.Name, edmItemType.TypeKind));
                                }
                            }

                            collectionWriter.WriteEnd();
                            collectionWriter.Flush();
                            break;
                        }

                        case EdmTypeKind.Complex:
                        {
                            Debug.Assert(model.GetClientTypeAnnotation(edmType).ElementType != null, "model.GetClientTypeAnnotation(edmType).ElementType != null");
                            ODataComplexValue complexValue = this.propertyConverter.CreateODataComplexValue(
                                model.GetClientTypeAnnotation(edmType).ElementType,
                                operationParameter.Value,
                                null /*propertyName*/,
                                false /*isCollectionItemType*/,
                                null /*visitedComplexTypeObjects*/);

                            Debug.Assert(complexValue != null, "complexValue != null");
                            parameterWriter.WriteValue(operationParameter.Name, complexValue);
                            break;
                        }

                        case EdmTypeKind.Primitive:
                            parameterWriter.WriteValue(operationParameter.Name, operationParameter.Value);
                            break;

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

                parameterWriter.WriteEnd();
                parameterWriter.Flush();
            }
        }