public EdmDeltaModel(IEdmModel source, IEdmEntityType entityType, IEnumerable<string> propertyNames)
        {
            _source = source;
            _entityType = new EdmEntityType(entityType.Namespace, entityType.Name);

            foreach (var property in entityType.StructuralProperties())
            {
                if (propertyNames.Contains(property.Name))
                    _entityType.AddStructuralProperty(property.Name, property.Type, property.DefaultValueString, property.ConcurrencyMode);
            }

            foreach (var property in entityType.NavigationProperties())
            {
                if (propertyNames.Contains(property.Name))
                {
                    var navInfo = new EdmNavigationPropertyInfo()
                    {
                        ContainsTarget = property.ContainsTarget,
                        DependentProperties = property.DependentProperties(),
                        PrincipalProperties = property.PrincipalProperties(),
                        Name = property.Name,
                        OnDelete = property.OnDelete,
                        Target = property.Partner != null 
                            ? property.Partner.DeclaringEntityType()
                            : property.Type.TypeKind() == EdmTypeKind.Collection
                            ? (property.Type.Definition as IEdmCollectionType).ElementType.Definition as IEdmEntityType
                            : property.Type.TypeKind() == EdmTypeKind.Entity
                            ? property.Type.Definition as IEdmEntityType
                            : null,
                        TargetMultiplicity = property.TargetMultiplicity(),
                    };
                    _entityType.AddUnidirectionalNavigation(navInfo);
                }
            }
        }
        internal void VisitEdmReferences(IEdmModel model)
        {
            IEnumerable<IEdmReference> references = model.GetEdmReferences();
            if (model != null && references != null)
            {
                foreach (IEdmReference tmp in references)
                {
                    this.schemaWriter.WriteReferenceElementHeader(tmp);
                    if (tmp.Includes != null)
                    {
                        foreach (IEdmInclude include in tmp.Includes)
                        {
                            this.schemaWriter.WriteIncludeElement(include);
                        }
                    }

                    if (tmp.IncludeAnnotations != null)
                    {
                        foreach (IEdmIncludeAnnotations includeAnnotations in tmp.IncludeAnnotations)
                        {
                            this.schemaWriter.WriteIncludeAnnotationsElement(includeAnnotations);
                        }
                    }

                    this.schemaWriter.WriteEndElement();
                }
            }
        }
        public ODataFeedSerializerTests()
        {
            _model = SerializationTestsHelpers.SimpleCustomerOrderModel();
            _customerSet = _model.FindDeclaredEntityContainer("Default.Container").FindEntitySet("Customers");
            _customers = new[] {
                new Customer()
                {
                    FirstName = "Foo",
                    LastName = "Bar",
                    ID = 10,
                },
                new Customer()
                {
                    FirstName = "Foo",
                    LastName = "Bar",
                    ID = 42,
                }
            };

            _customersType = new EdmCollectionTypeReference(
                    new EdmCollectionType(
                        new EdmEntityTypeReference(
                            _customerSet.ElementType,
                            isNullable: false)),
                    isNullable: false);

            _urlHelper = new Mock<UrlHelper>(new HttpRequestMessage()).Object;
            _writeContext = new ODataSerializerWriteContext(new ODataResponseContext()) { EntitySet = _customerSet, UrlHelper = _urlHelper };
        }
        //-----------------------------------------------------------------------------------------------------------------------------------------------------
        private IEdmModel LoadServiceModel()
        {
            _edmModel = LoadModelFromService(this.GetMetadataUri());
            _remoteEntityTypesNamespace = _edmModel.GetEntityNamespace();

            return _edmModel;
        }
 public ODataAdapter(ISession session, string protocolVersion, string metadataString)
     : this(session, protocolVersion)
 {
     var reader = XmlReader.Create(new StringReader(metadataString));
     reader.MoveToContent();
     Model = EdmxReader.Parse(reader);
 }
        private static void BuildOrderss(IEdmModel model)
        {
            IEdmEntityType orderType = model.SchemaElements.OfType<IEdmEntityType>().First(e => e.Name == "Order");

            Guid[] guids =
            {
                new Guid("196B3584-EF3D-41FD-90B4-76D59F9B929C"),
                new Guid("6CED5600-28BA-40EE-A2DF-E80AFADBE6C7"),
                new Guid("75036B94-C836-4946-8CC8-054CF54060EC"),
                new Guid("B3FF5460-6E77-4678-B959-DCC1C4937FA7"),
                new Guid("ED773C85-4E3C-4FC4-A3E9-9F1DA0A626DA")
            };

            IEdmEntityObject[] untypedOrders = new IEdmEntityObject[5];
            for (int i = 0; i < 5; i++)
            {
                dynamic untypedOrder = new EdmEntityObject(orderType);
                untypedOrder.OrderId = i;
                untypedOrder.Name = string.Format("Order-{0}", i);
                untypedOrder.Token = guids[i];
                untypedOrder.Amount = 10 + i;
                untypedOrders[i] = untypedOrder;
            }

            IEdmCollectionTypeReference entityCollectionType =
                new EdmCollectionTypeReference(
                    new EdmCollectionType(
                        new EdmEntityTypeReference(orderType, isNullable: false)));

            Orders = new EdmEntityObjectCollection(entityCollectionType, untypedOrders.ToList());
        }
        /// <summary>
        /// Resolve navigation source from model.
        /// </summary>
        /// <param name="model">The model to be used.</param>
        /// <param name="identifier">The identifier to be resolved.</param>
        /// <returns>The resolved navigation source.</returns>
        public virtual IEdmNavigationSource ResolveNavigationSource(IEdmModel model, string identifier)
        {
            if (EnableCaseInsensitive)
            {
                IEdmEntityContainer container = model.EntityContainer;
                if (container == null)
                {
                    return null;
                }

                var result = container.Elements.OfType<IEdmNavigationSource>()
                    .Where(source => string.Equals(identifier, source.Name, StringComparison.OrdinalIgnoreCase)).ToList();

                if (result.Count == 1)
                {
                    return result.Single();
                }
                else if (result.Count > 1)
                {
                    throw new ODataException(Strings.UriParserMetadata_MultipleMatchingNavigationSourcesFound(identifier));
                }
            }

            return model.FindDeclaredNavigationSource(identifier);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataPathRouteConstraint" /> class.
        /// </summary>
        /// <param name="pathHandler">The OData path handler to use for parsing.</param>
        /// <param name="model">The EDM model to use for parsing the path.</param>
        /// <param name="routeName">The name of the route this constraint is associated with.</param>
        /// <param name="routingConventions">The OData routing conventions to use for selecting the controller name.</param>
        public ODataPathRouteConstraint(IODataPathHandler pathHandler, IEdmModel model, string routeName, IEnumerable<IODataRoutingConvention> routingConventions)
        {
            if (pathHandler == null)
            {
                throw Error.ArgumentNull("pathHandler");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (routeName == null)
            {
                throw Error.ArgumentNull("routeName");
            }

            if (routingConventions == null)
            {
                throw Error.ArgumentNull("routingConventions");
            }

            PathHandler = pathHandler;
            EdmModel = model;
            RouteName = routeName;
            RoutingConventions = routingConventions;
        }
        private static void BuildCustomers(IEdmModel model)
        {
            IEdmEntityType customerType = model.SchemaElements.OfType<IEdmEntityType>().First(e => e.Name == "Customer");

            IEdmEntityObject[] untypedCustomers = new IEdmEntityObject[6];
            for (int i = 1; i <= 5; i++)
            {
                dynamic untypedCustomer = new EdmEntityObject(customerType);
                untypedCustomer.ID = i;
                untypedCustomer.Name = string.Format("Name {0}", i);
                untypedCustomer.SSN = "SSN-" + i + "-" + (100 + i);
                untypedCustomers[i-1] = untypedCustomer;
            }

            // create a special customer for "PATCH"
            dynamic customer = new EdmEntityObject(customerType);
            customer.ID = 6;
            customer.Name = "Name 6";
            customer.SSN = "SSN-6-T-006";
            untypedCustomers[5] = customer;

            IEdmCollectionTypeReference entityCollectionType =
                new EdmCollectionTypeReference(
                    new EdmCollectionType(
                        new EdmEntityTypeReference(customerType, isNullable: false)));

            Customers = new EdmEntityObjectCollection(entityCollectionType, untypedCustomers.ToList());
        }
        /// <summary>
        /// Parses the specified OData path as an <see cref="ODataPath"/> that contains additional information about the EDM type and entity set for the path.
        /// </summary>
        /// <param name="model">The model to use for path parsing.</param>
        /// <param name="odataPath">The OData path to parse.</param>
        /// <returns>A parsed representation of the path, or <c>null</c> if the path does not match the model.</returns>
        public virtual ODataPath Parse(IEdmModel model, string odataPath)
        {
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (odataPath == null)
            {
                throw Error.ArgumentNull("odataPath");
            }

            List<ODataPathSegment> pathSegments = new List<ODataPathSegment>();
            ODataPathSegment pathSegment = null;
            IEdmType previousEdmType = null;
            foreach (string segment in ParseSegments(odataPath))
            {
                pathSegment = ParseNextSegment(model, pathSegment, previousEdmType, segment);

                // If the Uri stops matching the model at any point, return null
                if (pathSegment == null)
                {
                    return null;
                }

                pathSegments.Add(pathSegment);
                previousEdmType = pathSegment.GetEdmType(previousEdmType);
            }
            return new ODataPath(pathSegments);
        }
        public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model,
            IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler)
        {
            if (routes == null)
            {
                throw Error.ArgumentNull("routes");
            }

            if (!String.IsNullOrEmpty(routePrefix))
            {
                int prefixLastIndex = routePrefix.Length - 1;
                if (routePrefix[prefixLastIndex] == '/')
                {
                    // Remove the last trailing slash if it has one.
                    routePrefix = routePrefix.Substring(0, routePrefix.Length - 1);
                }
            }

            if (batchHandler != null)
            {
                batchHandler.ODataRouteName = routeName;
                string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch;
                routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler);
            }

            ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions);
            routes.Add(routeName, new ODataRoute(routePrefix, routeConstraint));
        }
        public ODataSingletonDeserializerTest()
        {
            EdmModel model = new EdmModel();
            var employeeType = new EdmEntityType("NS", "Employee");
            employeeType.AddStructuralProperty("EmployeeId", EdmPrimitiveTypeKind.Int32);
            employeeType.AddStructuralProperty("EmployeeName", EdmPrimitiveTypeKind.String);
            model.AddElement(employeeType);

            EdmEntityContainer defaultContainer = new EdmEntityContainer("NS", "Default");
            model.AddElement(defaultContainer);

            _singleton = new EdmSingleton(defaultContainer, "CEO", employeeType);
            defaultContainer.AddElement(_singleton);

            model.SetAnnotationValue<ClrTypeAnnotation>(employeeType, new ClrTypeAnnotation(typeof(EmployeeModel)));

            _edmModel = model;
            _edmContainer = defaultContainer;

            _readContext = new ODataDeserializerContext
            {
                Path = new ODataPath(new SingletonPathSegment(_singleton)),
                Model = _edmModel,
                ResourceType = typeof(EmployeeModel)
            }; 

            _deserializerProvider = new DefaultODataDeserializerProvider();
        }
        public ODataUriResolver CreateResolver(IEdmModel model)
        {
            ODataUriResolver resolver;
            if (UnqualifiedNameCall && EnumPrefixFree)
            {
                resolver = new UnqualifiedCallAndEnumPrefixFreeResolver();
            }
            else if (UnqualifiedNameCall)
            {
                resolver = new UnqualifiedODataUriResolver();
            }
            else if (EnumPrefixFree)
            {
                resolver = new StringAsEnumResolver();
            }
            else if (AlternateKeys)
            {
                resolver = new AlternateKeysODataUriResolver(model);
            }
            else
            {
                resolver = new ODataUriResolver();
            }

            resolver.EnableCaseInsensitive = CaseInsensitive;
            return resolver;
        }
        static InstanceAnnotationsReaderIntegrationTests()
        {
            EdmModel modelTmp = new EdmModel();
            EntityType = new EdmEntityType("TestNamespace", "TestEntityType");
            modelTmp.AddElement(EntityType);

            var keyProperty = new EdmStructuralProperty(EntityType, "ID", EdmCoreModel.Instance.GetInt32(false));
            EntityType.AddKeys(new IEdmStructuralProperty[] { keyProperty });
            EntityType.AddProperty(keyProperty);
            var resourceNavigationProperty = EntityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "ResourceNavigationProperty", Target = EntityType, TargetMultiplicity = EdmMultiplicity.ZeroOrOne });
            var resourceSetNavigationProperty = EntityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "ResourceSetNavigationProperty", Target = EntityType, TargetMultiplicity = EdmMultiplicity.Many });

            var defaultContainer = new EdmEntityContainer("TestNamespace", "DefaultContainer_sub");
            modelTmp.AddElement(defaultContainer);
            EntitySet = new EdmEntitySet(defaultContainer, "TestEntitySet", EntityType);
            EntitySet.AddNavigationTarget(resourceNavigationProperty, EntitySet);
            EntitySet.AddNavigationTarget(resourceSetNavigationProperty, EntitySet);
            defaultContainer.AddElement(EntitySet);

            Singleton = new EdmSingleton(defaultContainer, "TestSingleton", EntityType);
            Singleton.AddNavigationTarget(resourceNavigationProperty, EntitySet);
            Singleton.AddNavigationTarget(resourceSetNavigationProperty, EntitySet);
            defaultContainer.AddElement(Singleton);

            ComplexType = new EdmComplexType("TestNamespace", "TestComplexType");
            ComplexType.AddProperty(new EdmStructuralProperty(ComplexType, "StringProperty", EdmCoreModel.Instance.GetString(false)));
            modelTmp.AddElement(ComplexType);

            Model = TestUtils.WrapReferencedModelsToMainModel("TestNamespace", "DefaultContainer", modelTmp);
        }
        /// <summary>
        /// Constructs an instance of <see cref="ODataQueryContext"/> with EdmModel and Entity's CLR type. 
        /// By default we assume the full name of the CLR type is used for the name for the EntitySet stored in the model.
        /// </summary>
        /// <param name="model">The EdmModel that includes the Entity and EntitySet information.</param>
        /// <param name="entityClrType">The entity's CLR type information.</param>
        public ODataQueryContext(IEdmModel model, Type entityClrType)
        {
            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (entityClrType == null)
            {
                throw Error.ArgumentNull("entityClrType");
            }

            // check if we can successfully retrieve an entitySet from the model with the given entityClrType
            IEnumerable<IEdmEntityContainer> containers = model.EntityContainers();
            List<IEdmEntitySet> entities = new List<IEdmEntitySet>();
            foreach (IEdmEntityContainer container in containers)
            {
                entities.AddRange(container.EntitySets().Where(s => s.ElementType.IsEquivalentTo(model.GetEdmType(entityClrType))));
            }

            if (entities == null || entities.Count == 0)
            {
                throw Error.InvalidOperation(SRResources.EntitySetNotFound, entityClrType.FullName);
            }

            if (entities.Count > 1)
            {
                throw Error.InvalidOperation(SRResources.MultipleEntitySetMatchedClrType, entityClrType.FullName);
            }

            Model = model;
            EntityClrType = entityClrType;
            EntitySet = entities[0];
        }
 public static IQueryable OrderByProperty(IQueryable query, IEdmModel model, IEdmProperty property, OrderByDirection direction, Type type, bool alreadyOrdered = false)
 {
     // property aliasing
     string propertyName = EdmLibHelpers.GetClrPropertyName(property, model);
     LambdaExpression orderByLambda = GetPropertyAccessLambda(type, propertyName);
     return OrderBy(query, orderByLambda, direction, type, alreadyOrdered);
 }
        public ODataFeedSerializerTests()
        {
            _model = SerializationTestsHelpers.SimpleCustomerOrderModel();
            _customerSet = _model.FindDeclaredEntityContainer("Default.Container").FindEntitySet("Customers");
            _customers = new[] {
                new Customer()
                {
                    FirstName = "Foo",
                    LastName = "Bar",
                    ID = 10,
                },
                new Customer()
                {
                    FirstName = "Foo",
                    LastName = "Bar",
                    ID = 42,
                }
            };

            _customersType = new EdmCollectionTypeReference(
                    new EdmCollectionType(
                        new EdmEntityTypeReference(
                            _customerSet.ElementType,
                            isNullable: false)),
                    isNullable: false);

            _writeContext = new ODataSerializerContext() { EntitySet = _customerSet, Model = _model };
        }
        /// <inheritdoc />
        public override ODataDeserializer GetODataDeserializer(IEdmModel model, Type type, HttpRequestMessage request)
        {
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (type == typeof(Uri))
            {
                return _entityReferenceLinkDeserializer;
            }

            if (type == typeof(ODataActionParameters) || type == typeof(ODataUntypedActionParameters))
            {
                return _actionPayloadDeserializer;
            }

            ClrTypeCache typeMappingCache = model.GetTypeMappingCache();
            IEdmTypeReference edmType = typeMappingCache.GetEdmType(type, model);

            if (edmType == null)
            {
                return null;
            }
            else
            {
                return GetEdmTypeDeserializer(edmType);
            }
        }
        public ODataComplexTypeSerializerTests()
        {
            _model = SerializationTestsHelpers.SimpleCustomerOrderModel();
            _address = new Address()
            {
                Street = "One Microsoft Way",
                City = "Redmond",
                State = "Washington",
                Country = "United States",
                ZipCode = "98052"
            };

            _addressType = _model.FindDeclaredType("Default.Address") as IEdmComplexType;
            _model.SetAnnotationValue(_addressType, new ClrTypeAnnotation(typeof(Address)));
            _addressTypeRef = _addressType.ToEdmTypeReference(isNullable: false).AsComplex();

            var cnAddressType = _model.FindDeclaredType("Default.CnAddress") as IEdmComplexType;
            _model.SetAnnotationValue(cnAddressType, new ClrTypeAnnotation(typeof(CnAddress)));

            var usAddressType = _model.FindDeclaredType("Default.UsAddress") as IEdmComplexType;
            _model.SetAnnotationValue(usAddressType, new ClrTypeAnnotation(typeof(UsAddress)));

            _locationType = _model.FindDeclaredType("Default.Location") as IEdmComplexType;
            _model.SetAnnotationValue(_locationType, new ClrTypeAnnotation(typeof(Location)));
            _locationTypeRef = _locationType.ToEdmTypeReference(isNullable: false).AsComplex();

            ODataSerializerProvider serializerProvider = new DefaultODataSerializerProvider();
            _serializer = new ODataComplexTypeSerializer(serializerProvider);
            TimeZoneInfoHelper.TimeZone = null;
        }
        /// <summary>
        /// Build a wildcard selection item
        /// </summary>
        /// <param name="tokenIn">the token to bind to a wildcard</param>
        /// <param name="model">the model to search for this wildcard</param>
        /// <param name="item">the new wildcard selection item, if we found one</param>
        /// <returns>true if we successfully bound to a wildcard, false otherwise</returns>
        public static bool TryBindAsWildcard(PathSegmentToken tokenIn, IEdmModel model, out SelectItem item)
        {
            bool isTypeToken = tokenIn.IsNamespaceOrContainerQualified();
            bool wildcard = tokenIn.Identifier.EndsWith("*", StringComparison.Ordinal);

            if (isTypeToken && wildcard)
            {
                string namespaceName = tokenIn.Identifier.Substring(0, tokenIn.Identifier.Length - 2);

                if (model.DeclaredNamespaces.Any(declaredNamespace => declaredNamespace.Equals(namespaceName, StringComparison.Ordinal)))
                {
                    item = new NamespaceQualifiedWildcardSelectItem(namespaceName);
                    return true;
                }
            }

            if (tokenIn.Identifier == "*")
            {
                item = new WildcardSelectItem();
                return true;
            }

            item = null;
            return false;
        }
Exemple #21
0
        /// <summary>
        /// Creates an instance of TypeResolver class.
        /// </summary>
        /// <param name="model">The client model.</param>
        /// <param name="resolveTypeFromName">The callback to resolve client CLR types.</param>
        /// <param name="resolveNameFromType">The callback for resolving server type names.</param>
        /// <param name="serviceModel">The service model.</param>
        internal TypeResolver(ClientEdmModel model, Func<string, Type> resolveTypeFromName, Func<Type, string> resolveNameFromType, IEdmModel serviceModel)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(resolveTypeFromName != null, "resolveTypeFromName != null");
            Debug.Assert(resolveNameFromType != null, "resolveNameFromType != null");
            this.resolveTypeFromName = resolveTypeFromName;
            this.resolveNameFromType = resolveNameFromType;
            this.serviceModel = serviceModel;
            this.clientEdmModel = model;

            if (serviceModel != null && clientEdmModel != null)
            {
                if (clientEdmModel.EdmStructuredSchemaElements == null)
                {
                    clientEdmModel.EdmStructuredSchemaElements = serviceModel.SchemaElements.Where(se => se is IEdmStructuredType).ToList();
                }
                else
                {
                    foreach (var element in serviceModel.SchemaElements.Where(se => se is IEdmStructuredType))
                    {
                        if (!clientEdmModel.EdmStructuredSchemaElements.Contains(element))
                        {
                            clientEdmModel.EdmStructuredSchemaElements.Add(element);
                        }
                    }
                }
            }
        }
        private static void ValidateCount(ODataPathSegment segment, IEdmModel model)
        {
            Contract.Assert(segment != null);
            Contract.Assert(model != null);

            NavigationPathSegment navigationPathSegment = segment as NavigationPathSegment;
            if (navigationPathSegment != null)
            {
                if (EdmLibHelpers.IsNotCountable(navigationPathSegment.NavigationProperty, model))
                {
                    throw new InvalidOperationException(Error.Format(
                        SRResources.NotCountablePropertyUsedForCount,
                        navigationPathSegment.NavigationPropertyName));
                }
                return;
            }

            PropertyAccessPathSegment propertyAccessPathSegment = segment as PropertyAccessPathSegment;
            if (propertyAccessPathSegment != null)
            {
                if (EdmLibHelpers.IsNotCountable(propertyAccessPathSegment.Property, model))
                {
                    throw new InvalidOperationException(Error.Format(
                        SRResources.NotCountablePropertyUsedForCount,
                        propertyAccessPathSegment.PropertyName));
                }
            }
        }
        public ParameterAliasNodeTranslatorTest()
        {
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<ParameterAliasCustomer>("Customers");
            builder.EntitySet<ParameterAliasOrder>("Orders");

            builder.EntityType<ParameterAliasCustomer>().Function("CollectionFunctionCall")
                .ReturnsCollection<int>().Parameter<int>("p1");

            builder.EntityType<ParameterAliasCustomer>().Function("EntityCollectionFunctionCall")
                .ReturnsCollectionFromEntitySet<ParameterAliasCustomer>("Customers").Parameter<int>("p1");

            builder.EntityType<ParameterAliasCustomer>().Function("SingleEntityFunctionCall")
                .Returns<ParameterAliasCustomer>().Parameter<int>("p1");

            builder.EntityType<ParameterAliasCustomer>().Function("SingleEntityFunctionCallWithoutParameters")
                .Returns<ParameterAliasCustomer>();

            builder.EntityType<ParameterAliasCustomer>().Function("SingleValueFunctionCall")
                .Returns<int>().Parameter<int>("p1");

            _model = builder.GetEdmModel();
            _customersEntitySet = _model.FindDeclaredEntitySet("Customers");
            _customerEntityType = _customersEntitySet.EntityType();
            _parameterAliasMappedNode = new ConstantNode(123);
        }
        /// <summary>
        /// Constructs a new <see cref="JsonFullMetadataLevel"/>.
        /// </summary>
        /// <param name="metadataDocumentUri">The metadata document uri from the writer settings.</param>
        /// <param name="model">The Edm model.</param>
        internal JsonFullMetadataLevel(Uri metadataDocumentUri, IEdmModel model)
        {
            Debug.Assert(model != null, "model != null");

            this.metadataDocumentUri = metadataDocumentUri;
            this.model = model;
        }
        /// <summary>
        /// Sets the given EdmModel with the configuration.
        /// </summary>
        /// <param name="configuration">Configuration to be updated.</param>
        /// <param name="model">The EdmModel to update.</param>
        public static void SetEdmModel(this HttpConfiguration configuration, IEdmModel model)
        {
            if (configuration == null)
            {
                throw Error.ArgumentNull("configuration");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            if (configuration.GetODataFormatter() != null)
            {
                throw Error.NotSupported(
                    SRResources.EdmModelMismatch,
                    typeof(IEdmModel).Name,
                    typeof(ODataMediaTypeFormatter).Name,
                    "SetODataFormatter");
            }

            configuration.Properties.AddOrUpdate(EdmModelKey, model, (a, b) =>
                {
                    return model;
                });
        }
        /// <summary>
        /// Validates a type name to ensure that it's not an empty string and resolves it against the provided <paramref name="model"/>.
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeName">The type name to validate.</param>
        /// <param name="expectedTypeKind">The expected type kind for the given type name.</param>
        /// <returns>The type with the given name and kind if a user model was available, otherwise null.</returns>
        internal static IEdmType ResolveAndValidateTypeName(IEdmModel model, string typeName, EdmTypeKind expectedTypeKind)
        {
            Debug.Assert(model != null, "model != null");

            if (typeName == null)
            {
                // if we have metadata, the type name of an entry must not be null
                if (model.IsUserModel())
                {
                    throw new ODataException(Strings.WriterValidationUtils_MissingTypeNameWithMetadata);
                }

                return null;
            }

            if (typeName.Length == 0)
            {
                throw new ODataException(Strings.ValidationUtils_TypeNameMustNotBeEmpty);
            }

            if (!model.IsUserModel())
            {
                return null;
            }

            // If we do have metadata, lookup the type and translate it to a type.
            IEdmType resolvedType = MetadataUtils.ResolveTypeNameForWrite(model, typeName);
            if (resolvedType == null)
            {
                throw new ODataException(Strings.ValidationUtils_UnrecognizedTypeName(typeName));
            }

            ValidationUtils.ValidateTypeKind(resolvedType.TypeKind, expectedTypeKind, resolvedType.ODataFullName());
            return resolvedType;
        }
        /// <summary>
        /// Resolves and validates the Edm type for the given <paramref name="value"/>.
        /// </summary>
        /// <param name="model">The model to use.</param>
        /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param>
        /// <param name="value">The value in question to resolve the type for.</param>
        /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param>
        /// <returns>A type for the <paramref name="value"/> or null if no metadata is available.</returns>
        internal static IEdmTypeReference ResolveAndValidateTypeNameForValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataValue value, bool isOpenProperty)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(value != null, "value != null");

            ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue;
            if (primitiveValue != null)
            {
                Debug.Assert(primitiveValue.Value != null, "primitiveValue.Value != null");
                return EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType());
            }

            ODataComplexValue complexValue = value as ODataComplexValue;
            if (complexValue != null)
            {
                return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, complexValue.TypeName, EdmTypeKind.Complex, isOpenProperty);
            }

            ODataEnumValue enumValue = value as ODataEnumValue;
            if (enumValue != null)
            {
                return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, enumValue.TypeName, EdmTypeKind.Enum, isOpenProperty);
            }

            ODataCollectionValue collectionValue = (ODataCollectionValue)value;
            return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, collectionValue.TypeName, EdmTypeKind.Collection, isOpenProperty);
        }
        private static void ValidateRestrictions(SelectExpandClause selectExpandClause, IEdmModel edmModel)
        {
            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem;
                if (expandItem != null)
                {
                    NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment;
                    IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty;
                    if (EdmLibHelpers.IsNotExpandable(navigationProperty, edmModel))
                    {
                        throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand, navigationProperty.Name));
                    }
                    ValidateRestrictions(expandItem.SelectAndExpand, edmModel);
                }

                PathSelectItem pathSelectItem = selectItem as PathSelectItem;
                if (pathSelectItem != null)
                {
                    ODataPathSegment segment = pathSelectItem.SelectedPath.LastSegment;
                    NavigationPropertySegment navigationPropertySegment = segment as NavigationPropertySegment;
                    if (navigationPropertySegment != null)
                    {
                        IEdmNavigationProperty navigationProperty = navigationPropertySegment.NavigationProperty;
                        if (EdmLibHelpers.IsNotNavigable(navigationProperty, edmModel))
                        {
                            throw new ODataException(Error.Format(SRResources.NotNavigablePropertyUsedInNavigation, navigationProperty.Name));
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Returns a hash set of operation imports (actions and functions) in the given entry.
        /// </summary>
        /// <param name="entry">The entry in question.</param>
        /// <param name="model">The edm model to resolve operation imports.</param>
        /// <param name="metadataDocumentUri">The metadata document uri.</param>
        /// <returns>The hash set of operation imports (actions and functions) in the given entry.</returns>
        private static HashSet<IEdmOperation> GetOperationsInEntry(ODataEntry entry, IEdmModel model, Uri metadataDocumentUri)
        {
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(model != null, "model != null");
            Debug.Assert(metadataDocumentUri != null && metadataDocumentUri.IsAbsoluteUri, "metadataDocumentUri != null && metadataDocumentUri.IsAbsoluteUri");

            HashSet<IEdmOperation> edmOperationImportsInEntry = new HashSet<IEdmOperation>(EqualityComparer<IEdmOperation>.Default);
            IEnumerable<ODataOperation> operations = ODataUtilsInternal.ConcatEnumerables((IEnumerable<ODataOperation>)entry.NonComputedActions, (IEnumerable<ODataOperation>)entry.NonComputedFunctions);
            if (operations != null)
            {
                foreach (ODataOperation operation in operations)
                {
                    Debug.Assert(operation.Metadata != null, "operation.Metadata != null");
                    string operationMetadataString = UriUtils.UriToString(operation.Metadata);
                    Debug.Assert(
                        ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString),
                        "ODataJsonLightUtils.IsMetadataReferenceProperty(operationMetadataString)");
                    Debug.Assert(
                        operationMetadataString[0] == ODataConstants.ContextUriFragmentIndicator || metadataDocumentUri.IsBaseOf(operation.Metadata),
                        "operationMetadataString[0] == JsonLightConstants.ContextUriFragmentIndicator || metadataDocumentUri.IsBaseOf(operation.Metadata)");

                    string fullyQualifiedOperationName = ODataJsonLightUtils.GetUriFragmentFromMetadataReferencePropertyName(metadataDocumentUri, operationMetadataString);
                    IEnumerable<IEdmOperation> edmOperations = model.ResolveOperations(fullyQualifiedOperationName);
                    if (edmOperations != null)
                    {
                        foreach (IEdmOperation edmOperation in edmOperations)
                        {
                            edmOperationImportsInEntry.Add(edmOperation);
                        }
                    }
                }
            }

            return edmOperationImportsInEntry;
        }
        public static FunctionPathSegment TryResolve(IEnumerable<IEdmFunctionImport> functions, IEdmModel model, string nextSegment)
        {
            Dictionary<string, string> parameters = null;
            IEnumerable<string> parameterNames = null;
            if (IsEnclosedInParentheses(nextSegment))
            {
                string value = nextSegment.Substring(1, nextSegment.Length - 2);
                parameters = KeyValueParser.ParseKeys(value);
                parameterNames = parameters.Keys;
            }

            IEdmFunctionImport function = FindBestFunction(functions, parameterNames);
            if (function != null)
            {
                if (GetNonBindingParameters(function).Any())
                {
                    return new FunctionPathSegment(function, model, parameters);
                }
                else
                {
                    return new FunctionPathSegment(function, model, parameterValues: null);
                }
            }

            return null;
        }
        /// <summary>
        /// Converts the given string <paramref name="value"/> to an ODataComplexValue or ODataCollectionValue and returns it.
        /// Tries in both JSON light and Verbose JSON.
        /// </summary>
        /// <remarks>Does not handle primitive values.</remarks>
        /// <param name="value">Value to be deserialized.</param>
        /// <param name="version">ODataVersion to be compliant with.</param>
        /// <param name="model">Model to use for verification.</param>
        /// <param name="typeReference">Expected type reference from deserialization. If null, verification will be skipped.</param>
        /// <returns>An ODataComplexValue or ODataCollectionValue that results from the deserialization of <paramref name="value"/>.</returns>
        internal static object ConvertFromComplexOrCollectionValue(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference)
        {
            ODataMessageReaderSettings settings = new ODataMessageReaderSettings();

            using (StringReader reader = new StringReader(value))
            {
                using (ODataJsonLightInputContext context = new ODataJsonLightInputContext(
                           ODataFormat.Json,
                           reader,
                           new MediaType(MimeConstants.MimeApplicationType, MimeConstants.MimeJsonSubType),
                           settings,
                           version,
                           false /*readingResponse*/,
                           true /*synchronous*/,
                           model,
                           null /*urlResolver*/,
                           null /*payloadKindDetectionState*/))
                {
                    ODataJsonLightPropertyAndValueDeserializer deserializer = new ODataJsonLightPropertyAndValueDeserializer(context);

                    // TODO: The way JSON array literals look in the URI is different that response payload with an array in it.
                    // The fact that we have to manually setup the underlying reader shows this different in the protocol.
                    // There is a discussion on if we should change this or not.
                    deserializer.JsonReader.Read(); // Move to first thing
                    object rawResult = deserializer.ReadNonEntityValue(
                        null /*payloadTypeName*/,
                        typeReference,
                        null /*DuplicatePropertyNameChecker*/,
                        null /*CollectionWithoutExpectedTypeValidator*/,
                        true /*validateNullValue*/,
                        false /*isTopLevelPropertyValue*/,
                        false /*insideComplexValue*/,
                        null /*propertyName*/);
                    deserializer.ReadPayloadEnd(false);

                    Debug.Assert(rawResult is ODataComplexValue || rawResult is ODataCollectionValue, "rawResult is ODataComplexValue || rawResult is ODataCollectionValue");
                    return(rawResult);
                }
            }
        }
Exemple #32
0
 private static IEnumerable <ODataInputFormatter> CreateInputFormatters(IEdmModel model = null)
 {
     // Model is not used in AspNetCore.
     return(ODataInputFormatterFactory.Create());
 }
Exemple #33
0
            private void WriteNamespaceDeep(IEdmModel edmModel, string @namespace)
            {
                var allElements = AllElementsByNamespace(edmModel.SchemaElements, @namespace).ToList();

                var types = AllTypes(allElements).ToList();

                foreach (var enumType in AllEnumTypes(types))
                {
                    var odcmEnum = TryResolveType <OdcmEnum>(enumType.Name, enumType.Namespace);

                    odcmEnum.UnderlyingType = (OdcmPrimitiveType)ResolveType(enumType.UnderlyingType.Name, enumType.UnderlyingType.Namespace);
                    odcmEnum.IsFlags        = enumType.IsFlags;
                    AddVocabularyAnnotations(odcmEnum, enumType);

                    foreach (var enumMember in enumType.Members)
                    {
                        var odcmEnumMember = new OdcmEnumMember(enumMember.Name)
                        {
                            Value = ((EdmIntegerConstant)enumMember.Value).Value
                        };

                        AddVocabularyAnnotations(odcmEnumMember, enumMember);
                        odcmEnum.Members.Add(odcmEnumMember);
                    }
                }

                foreach (var typeDefinition in AllTypeDefinitions(types))
                {
                    var odcmTypeDefinition = TryResolveType <OdcmTypeDefinition>(typeDefinition.Name, typeDefinition.Namespace);

                    // Type definitions should only support primitives as their base types [http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part3-csdl.html]
                    var baseType = ResolveType(typeDefinition.UnderlyingType.Name, typeDefinition.UnderlyingType.Namespace) as OdcmPrimitiveType;
                    if (baseType == null)
                    {
                        throw new InvalidOperationException("Type definitions should only accept primitive type as their base type.");
                    }

                    odcmTypeDefinition.BaseType = baseType;
                }

                foreach (var complexType in AllComplexTypes(types))
                {
                    var odcmClass = TryResolveType <OdcmClass>(complexType.Name, complexType.Namespace);

                    odcmClass.IsAbstract = complexType.IsAbstract;
                    odcmClass.IsOpen     = complexType.IsOpen;
                    AddVocabularyAnnotations(odcmClass, complexType);

                    ResolveBaseClass(odcmClass, complexType);

                    foreach (var property in complexType.DeclaredProperties)
                    {
                        WriteProperty(odcmClass, property);
                    }
                }

                var entityTypes = AllEntityTypes(types).ToList();

                // First make a pass through entity types to establish their hierarchy;
                // this is useful for cases when base entity type is defined after derived one
                foreach (var entityType in entityTypes)
                {
                    var odcmClass = TryResolveType <OdcmEntityClass>(entityType.Name, entityType.Namespace);

                    ResolveBaseClass(odcmClass, entityType);
                }

                foreach (var entityType in entityTypes)
                {
                    var odcmClass = TryResolveType <OdcmEntityClass>(entityType.Name, entityType.Namespace);

                    odcmClass.IsAbstract = entityType.IsAbstract;
                    odcmClass.IsOpen     = entityType.IsOpen;

                    foreach (var property in entityType.DeclaredProperties)
                    {
                        WriteProperty(odcmClass, property);
                    }

                    foreach (IEdmStructuralProperty keyProperty in entityType.Key())
                    {
                        OdcmProperty property;
                        if (!odcmClass.TryFindProperty(keyProperty.Name, out property))
                        {
                            throw new InvalidOperationException();
                        }

                        if (property.IsNullable)
                        {
                            //TODO: need to create a warning...
                        }

                        odcmClass.Key.Add(property);
                    }

                    AddVocabularyAnnotations(odcmClass, entityType);
                }

                foreach (var entityContainer in AllEntityContainers(allElements))
                {
                    var odcmClass = TryResolveType <OdcmClass>(entityContainer.Name, entityContainer.Namespace);

                    odcmClass.Projection = new OdcmProjection
                    {
                        Type = odcmClass
                    };

                    _propertyCapabilitiesCache.Add(odcmClass, new List <OdcmCapability>());
                    AddVocabularyAnnotations(odcmClass, entityContainer);

                    var entitySets = ContainerElementsByKind <IEdmEntitySet>(entityContainer, EdmContainerElementKind.EntitySet);
                    foreach (var entitySet in entitySets)
                    {
                        WriteProperty(odcmClass, entitySet);
                    }

                    var singletons = ContainerElementsByKind <IEdmSingleton>(entityContainer, EdmContainerElementKind.Singleton);
                    foreach (var singleton in singletons)
                    {
                        WriteProperty(odcmClass, singleton);
                    }

                    var actionImports = ContainerElementsByKind <IEdmActionImport>(entityContainer, EdmContainerElementKind.ActionImport);
                    foreach (var actionImport in actionImports)
                    {
                        WriteMethodImport(odcmClass, actionImport.Action, actionImport);
                    }

                    var functionImports = ContainerElementsByKind <IEdmFunctionImport>(entityContainer, EdmContainerElementKind.FunctionImport);
                    foreach (var functionImport in functionImports)
                    {
                        WriteMethodImport(odcmClass, functionImport.Function, functionImport);
                    }
                }
            }
Exemple #34
0
 public OeQueryExpression(IEdmModel edmModel, IEdmEntitySet entitySet, Expression expression)
 {
     EdmModel    = edmModel;
     _entitySet  = entitySet;
     _expression = new OeEnumerableToQuerableVisitor().Visit(expression);
 }
Exemple #35
0
        private void ValidateRestrictions(
            int?remainDepth,
            int currentDepth,
            SelectExpandClause selectExpandClause,
            IEdmNavigationProperty navigationProperty,
            ODataValidationSettings validationSettings)
        {
            IEdmModel edmModel = _selectExpandQueryOption.Context.Model;
            int?      depth    = remainDepth;

            if (remainDepth < 0)
            {
                throw new ODataException(
                          Error.Format(SRResources.MaxExpandDepthExceeded, currentDepth - 1, "MaxExpansionDepth"));
            }

            IEdmProperty       pathProperty;
            IEdmStructuredType pathStructuredType;

            if (navigationProperty == null)
            {
                pathProperty       = _selectExpandQueryOption.Context.TargetProperty;
                pathStructuredType = _selectExpandQueryOption.Context.TargetStructuredType;
            }
            else
            {
                pathProperty       = navigationProperty;
                pathStructuredType = navigationProperty.ToEntityType();
            }

            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem;
                if (expandItem != null)
                {
                    NavigationPropertySegment navigationSegment =
                        (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment;
                    IEdmNavigationProperty property = navigationSegment.NavigationProperty;
                    if (EdmHelpers.IsNotExpandable(property, edmModel))
                    {
                        throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand,
                                                              property.Name));
                    }

                    if (edmModel != null)
                    {
                        ValidateOtherQueryOptionInExpand(property, edmModel, expandItem, validationSettings);
                        bool isExpandable;
                        ExpandConfiguration expandConfiguration;
                        isExpandable = EdmHelpers.IsExpandable(property.Name,
                                                               pathProperty,
                                                               pathStructuredType,
                                                               edmModel,
                                                               out expandConfiguration);
                        if (isExpandable)
                        {
                            int maxDepth = expandConfiguration.MaxDepth;
                            if (maxDepth > 0 && (remainDepth == null || maxDepth < remainDepth))
                            {
                                remainDepth = maxDepth;
                            }
                        }
                        else if (!isExpandable)
                        {
                            if (!_defaultQuerySettings.EnableExpand ||
                                (expandConfiguration != null && expandConfiguration.ExpandType == SelectExpandType.Disabled))
                            {
                                throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand,
                                                                      property.Name));
                            }
                        }
                    }

                    if (remainDepth.HasValue)
                    {
                        remainDepth--;
                        if (expandItem.LevelsOption != null)
                        {
                            ValidateLevelsOption(expandItem.LevelsOption, remainDepth.Value, currentDepth + 1, edmModel,
                                                 property);
                        }
                    }

                    ValidateRestrictions(remainDepth, currentDepth + 1, expandItem.SelectAndExpand, property,
                                         validationSettings);
                    remainDepth = depth;
                }

                ValidateSelectItem(selectItem, pathProperty, pathStructuredType, edmModel);
            }
        }
Exemple #36
0
 private void ValidateFilterInExpand(IEdmProperty property, IEdmStructuredType structuredType, IEdmModel edmModel,
                                     FilterClause filterClause, ODataValidationSettings validationSettings)
 {
     if (filterClause != null)
     {
         _filterQueryValidator.Validate(property, structuredType, filterClause, validationSettings, edmModel, _defaultQuerySettings);
     }
 }
Exemple #37
0
 private void ValidateCountInExpand(IEdmProperty property, IEdmStructuredType structuredType, IEdmModel edmModel,
                                    bool?countOption)
 {
     if (countOption == true)
     {
         if (EdmHelpers.IsNotCountable(
                 property,
                 structuredType,
                 edmModel,
                 _defaultQuerySettings.EnableCount))
         {
             throw new ODataException(Error.Format(SRResources.NotCountablePropertyUsedForCount, property.Name));
         }
     }
 }
        /// <summary>
        /// Verifies that the given <paramref name="primitiveValue"/> is or can be coerced to <paramref name="expectedTypeReference"/>, and coerces it if necessary.
        /// </summary>
        /// <param name="primitiveValue">An EDM primitive value to verify.</param>
        /// <param name="model">Model to verify against.</param>
        /// <param name="expectedTypeReference">Expected type reference.</param>
        /// <param name="version">The version to use for reading.</param>
        /// <returns>Coerced version of the <paramref name="primitiveValue"/>.</returns>
        internal static object VerifyAndCoerceUriPrimitiveLiteral(object primitiveValue, IEdmModel model, IEdmTypeReference expectedTypeReference, ODataVersion version)
        {
            ExceptionUtils.CheckArgumentNotNull(primitiveValue, "primitiveValue");
            ExceptionUtils.CheckArgumentNotNull(model, "model");
            ExceptionUtils.CheckArgumentNotNull(expectedTypeReference, "expectedTypeReference");

            // First deal with null literal
            ODataNullValue nullValue = primitiveValue as ODataNullValue;

            if (nullValue != null)
            {
                if (!expectedTypeReference.IsNullable)
                {
                    throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralNullOnNonNullableType(expectedTypeReference.ODataFullName()));
                }

                return(nullValue);
            }

            // Only other positive case is a numeric primitive that needs to be coerced
            IEdmPrimitiveTypeReference expectedPrimitiveTypeReference = expectedTypeReference.AsPrimitiveOrNull();

            if (expectedPrimitiveTypeReference == null)
            {
                throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedTypeReference.ODataFullName(), primitiveValue));
            }

            object coercedResult = CoerceNumericType(primitiveValue, expectedPrimitiveTypeReference.PrimitiveDefinition());

            if (coercedResult != null)
            {
                return(coercedResult);
            }

            Type actualType = primitiveValue.GetType();
            Type targetType = TypeUtils.GetNonNullableType(EdmLibraryExtensions.GetPrimitiveClrType(expectedPrimitiveTypeReference));

            // If target type is assignable from actual type, we're OK
            if (targetType.IsAssignableFrom(actualType))
            {
                return(primitiveValue);
            }

            throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeVerificationFailure(expectedPrimitiveTypeReference.ODataFullName(), primitiveValue));
        }
 /// <summary>
 /// Creates a new instance of the <see cref="SelectExpandNode"/> class describing the set of structural properties,
 /// nested properties, navigation properties, and actions to select and expand for the given <paramref name="selectExpandClause"/>.
 /// </summary>
 /// <param name="selectExpandClause">The parsed $select and $expand query options.</param>
 /// <param name="structuredType">The structural type of the resource that would be written.</param>
 /// <param name="model">The <see cref="IEdmModel"/> that contains the given structural type.</param>
 public SelectExpandNode(SelectExpandClause selectExpandClause, IEdmStructuredType structuredType, IEdmModel model)
     : this()
 {
     Initialize(selectExpandClause, structuredType, model, false);
 }
        /// <summary>
        /// Converts a <see cref="ODataCollectionValue"/> to a string for use in a Url.
        /// </summary>
        /// <param name="collectionValue">Instance to convert.</param>
        /// <param name="model">Model to be used for validation. User model is optional. The EdmLib core model is expected as a minimum.</param>
        /// <param name="version">Version to be compliant with. Collection requires >= V3.</param>
        /// <returns>A string representation of <paramref name="collectionValue"/> to be added to a Url.</returns>
        internal static string ConvertToUriCollectionLiteral(ODataCollectionValue collectionValue, IEdmModel model, ODataVersion version)
        {
            ExceptionUtils.CheckArgumentNotNull(collectionValue, "collectionValue");
            ExceptionUtils.CheckArgumentNotNull(model, "model");

            StringBuilder builder = new StringBuilder();

            using (TextWriter textWriter = new StringWriter(builder, CultureInfo.InvariantCulture))
            {
                ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings()
                {
                    Version = version,
                    Indent  = false
                };

                WriteJsonLightLiteral(
                    model,
                    messageWriterSettings,
                    textWriter,
                    (serializer) => serializer.WriteCollectionValue(
                        collectionValue,
                        null /*metadataTypeReference*/,
                        false /*isTopLevelProperty*/,
                        true /*isInUri*/,
                        false /*isOpenPropertyType*/));
            }

            return(builder.ToString());
        }
Exemple #41
0
        public void Annotate(IMetadataElement metadataElement, IEdmElement edmElement, IEdmModel edmModel)
        {
            if (metadataElement is EntityElement || metadataElement is EnumTypeElement)
            {
                edmModel.SetAnnotationValue(edmElement, AnnotationNamespace, AnnotationAttribute, metadataElement.Identity.Id);

                var clrType = _clrTypeProvider.Get(metadataElement.Identity);
                if (clrType != null)
                {
                    edmModel.SetAnnotationValue(edmElement, new ClrTypeAnnotation(clrType));
                }
            }
        }
 public FinanceTmpDPDocumentsControllerTest(SqliteDatabaseFixture fixture)
 {
     this.fixture  = fixture;
     this.provider = UnitTestUtility.GetServiceProvider();
     this.model    = UnitTestUtility.GetEdmModel <FinanceDocument>(provider, "FinanceDocuments");
 }
Exemple #43
0
        public static bool IsAutoExpand(IEdmProperty edmProperty, IEdmModel edmModel)
        {
            QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel);

            return(annotation == null ? false : annotation.Restrictions.AutoExpand);
        }
        /// <summary>
        /// Initialize the Node from <see cref="SelectExpandClause"/> for the given <see cref="IEdmStructuredType"/>.
        /// </summary>
        /// <param name="selectExpandClause">The input select and expand clause ($select and $expand).</param>
        /// <param name="structuredType">The related structural type to select and expand.</param>
        /// <param name="model">The Edm model.</param>
        /// <param name="expandedReference">Is expanded reference.</param>
        private void Initialize(SelectExpandClause selectExpandClause, IEdmStructuredType structuredType, IEdmModel model, bool expandedReference)
        {
            if (structuredType == null)
            {
                throw Error.ArgumentNull("structuredType");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            IEdmEntityType entityType = structuredType as IEdmEntityType;

            if (expandedReference)
            {
                SelectAllDynamicProperties = false;
                if (entityType != null)
                {
                    // only need to include the key properties.
                    SelectedStructuralProperties = new HashSet <IEdmStructuralProperty>(entityType.Key());
                }
            }
            else
            {
                EdmStructuralTypeInfo structuralTypeInfo = new EdmStructuralTypeInfo(model, structuredType);

                if (selectExpandClause == null)
                {
                    SelectAllDynamicProperties = true;

                    // includes navigation properties
                    SelectedNavigationProperties = structuralTypeInfo.AllNavigationProperties;

                    // includes all bound actions
                    SelectedActions = structuralTypeInfo.AllActions;

                    // includes all bound functions
                    SelectedFunctions = structuralTypeInfo.AllFunctions;

                    // includes all structural properties
                    if (structuralTypeInfo.AllStructuralProperties != null)
                    {
                        foreach (var property in structuralTypeInfo.AllStructuralProperties)
                        {
                            AddStructuralProperty(property, null);
                        }
                    }
                }
                else
                {
                    BuildSelectExpand(selectExpandClause, structuralTypeInfo);
                }

                AdjustSelectNavigationProperties();
            }
        }
Exemple #45
0
 public static Type GetClrType(IEdmType edmType, IEdmModel edmModel)
 {
     return(GetClrType(edmType, edmModel, _defaultAssemblyResolver));
 }
Exemple #46
0
        public static PropertyInfo GetDynamicPropertyDictionary(IEdmStructuredType edmType, IEdmModel edmModel)
        {
            if (edmType == null)
            {
                throw Error.ArgumentNull("edmType");
            }

            if (edmModel == null)
            {
                throw Error.ArgumentNull("edmModel");
            }

            DynamicPropertyDictionaryAnnotation annotation =
                edmModel.GetAnnotationValue <DynamicPropertyDictionaryAnnotation>(edmType);

            if (annotation != null)
            {
                return(annotation.PropertyInfo);
            }

            return(null);
        }
        public void Term_Constant_AllTypes_OnEntityType()
        {
            this.SetupModelsAndValues();

            // Not handled:
            //      <Annotation Term=""bar.GeographyValue"" Geography=""xxx"" />
            //      <Annotation Term=""bar.GeometryValue"" Geometry=""xxx"" />
            const string applicationCsdl =
                @"<Schema Namespace=""Annotations"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
    <Annotations Target=""foo.Person"">
        <Annotation Term=""bar.BinaryValue"" Binary=""1234"" />        
        <Annotation Term=""bar.BooleanValue"" Bool=""true"" />
        <Annotation Term=""bar.ByteValue"" Int=""255"" />
        <Annotation Term=""bar.DateValue"" Date=""2014-08-08"" />
        <Annotation Term=""bar.DateTimeOffsetValue"" DateTimeOffset=""2001-10-26T19:32:52+00:00"" />
        <Annotation Term=""bar.DecimalValue"" Decimal=""12.345"" />
        <Annotation Term=""bar.DoubleValue"" Float=""3.1416"" />
        <Annotation Term=""bar.GuidValue"" Guid=""4ae71c81-c21a-40a2-8d53-f1a29ed4a2f2"" />
        <Annotation Term=""bar.Int16Value"" Int=""0"" />
        <Annotation Term=""bar.Int32Value"" Int=""100"" />
        <Annotation Term=""bar.Int64Value"" Int=""9999"" />
        <Annotation Term=""bar.DurationValue"" Duration=""PT1M59S"" />
        <Annotation Term=""bar.SByteValue"" Int=""-128"" />
        <Annotation Term=""bar.SingleValue"" Float=""3.1416E10"" />
        <Annotation Term=""bar.StringValue"" String=""I am a string."" />
        <Annotation Term=""bar.TimeOfDayValue"" TimeOfDay=""1:30:59.123"" />
    </Annotations>
</Schema>";
            IEdmModel applicationModel = this.Parse(applicationCsdl, this.baseModel, this.vocabularyDefinitionModel);
            EdmExpressionEvaluator expressionEvaluator = new EdmExpressionEvaluator(this.operationsLookup);

            IEdmTerm  term;
            IEdmValue annotationValue;

            term            = this.vocabularyDefinitionModel.FindTerm("bar.BinaryValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            byte[] v = ((IEdmBinaryValue)annotationValue).Value;
            Assert.AreEqual(2, v.Length, "Binary value length");
            Assert.AreEqual(0x12, v[0], "Binary value");
            Assert.AreEqual(0x34, v[1], "Binary value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.BooleanValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(true, ((IEdmBooleanValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.ByteValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(255, ((IEdmIntegerValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.DateValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(new Date(2014, 8, 8), ((IEdmDateValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.DateTimeOffsetValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(DateTimeOffset.Parse("2001-10-26T19:32:52+00:00"), ((IEdmDateTimeOffsetValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.DecimalValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(12.345M, ((IEdmDecimalValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.DoubleValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(3.1416, ((IEdmFloatingValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.GuidValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(Guid.Parse("4ae71c81-c21a-40a2-8d53-f1a29ed4a2f2"), ((IEdmGuidValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.Int16Value");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(0, ((IEdmIntegerValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.Int32Value");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(100, ((IEdmIntegerValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.Int64Value");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(9999, ((IEdmIntegerValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.DurationValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(new TimeSpan(0, 1, 59), ((IEdmDurationValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.SByteValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(-128, ((IEdmIntegerValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.SingleValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(3.1416E10, ((IEdmFloatingValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.StringValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual("I am a string.", ((IEdmStringValue)annotationValue).Value, "Term annotation value");

            term            = this.vocabularyDefinitionModel.FindTerm("bar.TimeOfDayValue");
            annotationValue = applicationModel.GetTermValue(this.personValue, term, expressionEvaluator);
            Assert.AreEqual(new TimeOfDay(1, 30, 59, 123), ((IEdmTimeOfDayValue)annotationValue).Value, "Term annotation value");
        }
Exemple #48
0
        public static bool IsNotCountable(IEdmProperty edmProperty, IEdmModel edmModel)
        {
            QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel);

            return(annotation == null ? false : annotation.Restrictions.NotCountable);
        }
Exemple #49
0
        public void PayloadOrderTest()
        {
            ODataFeedAndEntrySerializationInfo infoMyType = new ODataFeedAndEntrySerializationInfo()
            {
                NavigationSourceEntityTypeName = "MyType",
                NavigationSourceName           = "MySet",
                ExpectedTypeName = "MyType"
            };

            ODataFeedAndEntrySerializationInfo infoAllInType = new ODataFeedAndEntrySerializationInfo()
            {
                NavigationSourceEntityTypeName = "TestModel.AllInType",
                NavigationSourceName           = "MySet",
                ExpectedTypeName = "TestModel.AllInType"
            };

            IEdmModel model = BuildPayloadOrderTestModel();

            IEnumerable <PayloadOrderTestCase> testCases = new []
            {
                new PayloadOrderTestCase
                {
                    DebugDescription = "TypeName at the beginning, nothing else",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "{0}  <id />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "TypeName at the beginning, changes at the end - the one from the beginning is used (also for validation).",
                    Entry            = new ODataEntry()
                    {
                        MediaResource = new ODataStreamReferenceValue(),
                        Properties    = new []
                        {
                            new ODataProperty {
                                Name = "ID", Value = 42
                            },
                            new ODataProperty {
                                Name = "Name", Value = "foo"
                            },
                        },
                        SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation
                    {
                        BeforeWriteStartCallback = (entry) => { entry.TypeName = "TestModel.AllInType"; },
                        BeforeWriteEndCallback   = (entry) => { entry.TypeName = "NonExistingType"; }
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Model = model,
                    Xml   = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#TestModel.AllInType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "{0}  <id />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "   <properties xmlns=\"http://docs.oasis-open.org/odata/ns/metadata\">",
                        "       <ID p3:type=\"Edm.Int32\" xmlns:p3=\"http://docs.oasis-open.org/odata/ns/metadata\" xmlns=\"http://docs.oasis-open.org/odata/ns/data\">42</ID>",
                        "       <Name xmlns=\"http://docs.oasis-open.org/odata/ns/data\">foo</Name>",
                        "   </properties>",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "Just ETag at the beginning, changed at the end - the one from the beginning should be used.",
                    Entry            = new ODataEntry()
                    {
                        SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation
                    {
                        BeforeWriteStartCallback = (entry) => { entry.ETag = "\"etag1\""; },
                        BeforeWriteEndCallback   = (entry) => { entry.ETag = "\"etag2\""; }
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry p1:etag=\"&quot;etag1&quot;\" xmlns:p1=\"http://docs.oasis-open.org/odata/ns/metadata\" xmlns=\"http://www.w3.org/2005/Atom\">",
                        "{0}  <id />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "No TypeName at the beginning, nothing else - should not write the category",
                    Entry            = new ODataEntry()
                    {
                        TypeName = null, SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "{0}  <id />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "TypeName and ID at the beginning",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", Id = new Uri("http://odata.org/MyId"), SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <id>urn:MyId</id>",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "{0}  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "TypeName and ID at the end",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation {
                        BeforeWriteStartCallback = (entry) => entry.Id = new Uri("http://odata.org/MyId"),
                        BeforeWriteEndCallback   = (entry) => entry.Id = new Uri("http://odata.org/MyId")
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "{0}  <id>urn:MyId</id>",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "TypeName, Self and Edit link at the beginning, Id at the end",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", ReadLink = ObjectModelUtils.DefaultEntryReadLink, EditLink = new Uri("http://odata.org/editlink"), SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation {
                        BeforeWriteStartCallback = (entry) => entry.Id = null,
                        BeforeWriteEndCallback   = (entry) => entry.Id = new Uri("http://odata.org/MyId")
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "  <link rel=\"edit\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "{0}  <id>urn:MyId</id>",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "Everything at the beginning",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", Id = new Uri("http://odata.org/MyId"), ReadLink = ObjectModelUtils.DefaultEntryReadLink, EditLink = new Uri("http://odata.org/editlink"), SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <id>urn:MyId</id>",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "  <link rel=\"edit\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "{0}  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "Everything at the end",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", Id = new Uri("http://odata.org/MyId"), SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation {
                        BeforeWriteStartCallback = (entry) => { entry.Id = null; entry.ReadLink = null; entry.EditLink = null; },
                        BeforeWriteEndCallback   = (entry) => { entry.Id = new Uri("http://odata.org/MyId"); entry.ReadLink = ObjectModelUtils.DefaultEntryReadLink; entry.EditLink = new Uri("http://odata.org/editlink"); }
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"/>",
                        "{0}  <id>urn:MyId</id>",
                        "  <link rel=\"edit\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "Everything at the beginning, category with type name, edit and self link with ATOM metadata",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", Id = new Uri("http://odata.org/MyId"), ReadLink = ObjectModelUtils.DefaultEntryReadLink, EditLink = new Uri("http://odata.org/editlink"), SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new AtomEntryMetadata {
                        EditLink = new AtomLinkMetadata {
                            Title = "EditLinkTitle"
                        },
                        SelfLink = new AtomLinkMetadata {
                            Title = "SelfLinkTitle"
                        },
                        CategoryWithTypeName = new AtomCategoryMetadata {
                            Label = "TypeNameLabel"
                        },
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <id>urn:MyId</id>",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\" label=\"TypeNameLabel\" />",
                        "  <link rel=\"edit\" title=\"EditLinkTitle\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" title=\"SelfLinkTitle\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "{0}  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "Everything at the end, category with type name, edit and self link with ATOM metadata (from the beginning)",
                    Entry            = new ODataEntry()
                    {
                        TypeName = "MyType", SerializationInfo = infoMyType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation {
                        BeforeWriteStartCallback = (entry) => { entry.Id = null; entry.ReadLink = null; entry.EditLink = null; },
                        BeforeWriteEndCallback   = (entry) => { entry.Id = new Uri("http://odata.org/MyId"); entry.ReadLink = ObjectModelUtils.DefaultEntryReadLink; entry.EditLink = new Uri("http://odata.org/editlink"); }
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        EditLink = new AtomLinkMetadata {
                            Title = "EditLinkTitle"
                        },
                        SelfLink = new AtomLinkMetadata {
                            Title = "SelfLinkTitle"
                        },
                        CategoryWithTypeName = new AtomCategoryMetadata {
                            Label = "TypeNameLabel"
                        },
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Xml = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#MyType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\" label=\"TypeNameLabel\" />",
                        "{0}  <id>urn:MyId</id>",
                        "  <link rel=\"edit\" title=\"EditLinkTitle\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" title=\"SelfLinkTitle\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <content type=\"application/xml\" />",
                        "</entry>"),
                },
                new PayloadOrderTestCase
                {
                    DebugDescription = "With default stream and stream property, everything at the end",
                    Entry            = new ODataEntry()
                    {
                        TypeName      = "TestModel.AllInType",
                        MediaResource = new ODataStreamReferenceValue
                        {
                            ReadLink    = new Uri("http://odata.org/mrreadlink"),
                            ContentType = "mr/type",
                            EditLink    = new Uri("http://odata.org/mreditlink")
                        },
                        Properties = new []
                        {
                            new ODataProperty {
                                Name = "ID", Value = 42
                            },
                            new ODataProperty {
                                Name = "Name", Value = "foo"
                            },
                            new ODataProperty {
                                Name = "Description", Value = "bar"
                            },
                            new ODataProperty {
                                Name = "StreamProperty", Value = new ODataStreamReferenceValue
                                {
                                    ReadLink    = new Uri("http://odata.org/streamproperty/readlink"),
                                    ContentType = "streamproperty/type",
                                    EditLink    = new Uri("http://odata.org/streamproperty/editlink"),
                                }
                            }
                        },
                        SerializationInfo = infoAllInType
                    }
                    .WithAnnotation(new WriteEntryCallbacksAnnotation {
                        BeforeWriteStartCallback = (entry) => { entry.Id = null; entry.ReadLink = null; entry.EditLink = null; },
                        BeforeWriteEndCallback   = (entry) => { entry.Id = new Uri("http://odata.org/MyId"); entry.ReadLink = ObjectModelUtils.DefaultEntryReadLink; entry.EditLink = new Uri("http://odata.org/editlink"); }
                    })
                    .WithAnnotation(new AtomEntryMetadata {
                        EditLink = new AtomLinkMetadata {
                            Title = "EditLinkTitle"
                        },
                        SelfLink = new AtomLinkMetadata {
                            Title = "SelfLinkTitle"
                        },
                        CategoryWithTypeName = new AtomCategoryMetadata {
                            Label = "TypeNameLabel"
                        },
                        Updated = ObjectModelUtils.DefaultEntryUpdatedDateTime
                    }),
                    Model = model,
                    Xml   = string.Join(
                        "$(NL)",
                        "<entry xmlns=\"" + TestAtomConstants.AtomNamespace + "\">",
                        "  <category term=\"#TestModel.AllInType\" scheme=\"http://docs.oasis-open.org/odata/ns/scheme\" label=\"TypeNameLabel\" />",
                        "{0}  <id>urn:MyId</id>",
                        "  <link rel=\"edit\" title=\"EditLinkTitle\" href=\"http://odata.org/editlink\" />",
                        "  <link rel=\"self\" title=\"SelfLinkTitle\" href=\"" + ObjectModelUtils.DefaultEntryReadLink.OriginalString + "\" />",
                        "  <title />",
                        "  <updated>2010-10-12T17:13:00Z</updated>",
                        "  <author>",
                        "    <name />",
                        "  </author>",
                        "  <link rel=\"http://docs.oasis-open.org/odata/ns/mediaresource/StreamProperty\" type=\"streamproperty/type\" title=\"StreamProperty\" href=\"http://odata.org/streamproperty/readlink\" />",
                        "  <link rel=\"http://docs.oasis-open.org/odata/ns/edit-media/StreamProperty\" type=\"streamproperty/type\" title=\"StreamProperty\" href=\"http://odata.org/streamproperty/editlink\" />",
                        "  <link rel=\"edit-media\" href=\"http://odata.org/mreditlink\" />",
                        "  <content type=\"mr/type\" src=\"http://odata.org/mrreadlink\" />",
                        "  <properties xmlns=\"http://docs.oasis-open.org/odata/ns/metadata\">",
                        "    <ID p3:type=\"Edm.Int32\" xmlns:p3=\"http://docs.oasis-open.org/odata/ns/metadata\" xmlns=\"http://docs.oasis-open.org/odata/ns/data\">42</ID>",
                        "    <Name xmlns=\"http://docs.oasis-open.org/odata/ns/data\">foo</Name>",
                        "    <Description xmlns=\"http://docs.oasis-open.org/odata/ns/data\">bar</Description>",
                        "  </properties>",
                        "</entry>"),
                    // Stream properties are not allowed in requests.
                    SkipTestConfiguration = tc => tc.IsRequest
                },
            };

            IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testDescriptors = testCases.Select(testCase =>
                                                                                                      new PayloadWriterTestDescriptor <ODataItem>(
                                                                                                          this.Settings,
                                                                                                          new ODataItem[] { testCase.Entry },
                                                                                                          tc => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
            {
                Xml = string.Format(CultureInfo.InvariantCulture, testCase.Xml, string.Empty),
                FragmentExtractor = (element) => element
            })
            {
                DebugDescription      = testCase.DebugDescription,
                Model                 = testCase.Model,
                SkipTestConfiguration = testCase.SkipTestConfiguration
            });

            testDescriptors = testDescriptors.Concat(testCases.Select(testCase =>
                                                                      new PayloadWriterTestDescriptor <ODataItem>(
                                                                          this.Settings,
                                                                          new ODataItem[] { testCase.Entry, new ODataNavigationLink
                                                                                            {
                                                                                                Name         = "NavProp",
                                                                                                IsCollection = true,
                                                                                                Url          = new Uri("http://odata.org/navprop/uri")
                                                                                            } },
                                                                          tc => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
            {
                Xml = string.Format(CultureInfo.InvariantCulture, testCase.Xml,
                                    "  <link rel=\"" + TestAtomConstants.ODataNavigationPropertiesRelatedLinkRelationPrefix + "NavProp\" " +
                                    "type=\"application/atom+xml;type=feed\" title=\"NavProp\" " +
                                    "href=\"http://odata.org/navprop/uri\" />$(NL)"),
                FragmentExtractor = (element) => element
            })
            {
                DebugDescription      = testCase.DebugDescription + "- with navigation property",
                Model                 = testCase.Model,
                SkipTestConfiguration = testCase.SkipTestConfiguration
            }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors,
                this.WriterTestConfigurationProvider.AtomFormatConfigurationsWithIndent,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);
                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor.DeferredLinksToEntityReferenceLinksInRequest(testConfiguration), testConfiguration, this.Assert, this.Logger);
            });
        }
Exemple #50
0
        private static IEdmType GetEdmType(IEdmModel edmModel, Type clrType, bool testCollections)
        {
            Contract.Assert(edmModel != null);
            Contract.Assert(clrType != null);

            IEdmPrimitiveType primitiveType = GetEdmPrimitiveTypeOrNull(clrType);

            if (primitiveType != null)
            {
                return(primitiveType);
            }
            else
            {
                if (testCollections)
                {
                    Type enumerableOfT = ExtractGenericInterface(clrType, typeof(IEnumerable <>));
                    if (enumerableOfT != null)
                    {
                        Type elementClrType = enumerableOfT.GetGenericArguments()[0];

                        // IEnumerable<SelectExpandWrapper<T>> is a collection of T.
                        Type entityType;
                        if (IsSelectExpandWrapper(elementClrType, out entityType))
                        {
                            elementClrType = entityType;
                        }

                        IEdmType elementType = GetEdmType(edmModel, elementClrType, testCollections: false);
                        if (elementType != null)
                        {
                            return(new EdmCollectionType(elementType.ToEdmTypeReference(IsNullable(elementClrType))));
                        }
                    }
                }

                Type underlyingType = TypeHelper.GetUnderlyingTypeOrSelf(clrType);
                if (underlyingType.IsEnum)
                {
                    clrType = underlyingType;
                }

                // search for the ClrTypeAnnotation and return it if present
                IEdmType returnType =
                    edmModel
                    .SchemaElements
                    .OfType <IEdmType>()
                    .Select(edmType => new { EdmType = edmType, Annotation = edmModel.GetAnnotationValue <ClrTypeAnnotation>(edmType) })
                    .Where(tuple => tuple.Annotation != null && tuple.Annotation.ClrType == clrType)
                    .Select(tuple => tuple.EdmType)
                    .SingleOrDefault();

                // default to the EdmType with the same name as the ClrType name
                returnType = returnType ?? edmModel.FindType(clrType.EdmFullName());

                if (clrType.BaseType != null)
                {
                    // go up the inheritance tree to see if we have a mapping defined for the base type.
                    returnType = returnType ?? GetEdmType(edmModel, clrType.BaseType, testCollections);
                }
                return(returnType);
            }
        }
Exemple #51
0
        /// <summary>
        /// Generates a string to be used as the skip token value within the next link.
        /// </summary>
        /// <param name="lastMember"> Object based on which SkipToken value will be generated.</param>
        /// <param name="model">The edm model.</param>
        /// <param name="orderByNodes">List of orderByNodes used to generate the skiptoken value.</param>
        /// <returns>Value for the skiptoken to be used in the next link.</returns>
        private static string GenerateSkipTokenValue(Object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes)
        {
            if (lastMember == null)
            {
                return(String.Empty);
            }

            IEnumerable <IEdmProperty> propertiesForSkipToken = GetPropertiesForSkipToken(lastMember, model, orderByNodes);
            StringBuilder skipTokenBuilder = new StringBuilder(String.Empty);

            if (propertiesForSkipToken == null)
            {
                return(skipTokenBuilder.ToString());
            }

            int    count = 0;
            string uriLiteral;
            object value;
            int    lastIndex         = propertiesForSkipToken.Count() - 1;
            IEdmStructuredObject obj = lastMember as IEdmStructuredObject;

            foreach (IEdmProperty edmProperty in propertiesForSkipToken)
            {
                bool   islast          = count == lastIndex;
                string clrPropertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, model);
                if (obj != null)
                {
                    obj.TryGetPropertyValue(clrPropertyName, out value);
                }
                else
                {
                    value = lastMember.GetType().GetProperty(clrPropertyName).GetValue(lastMember);
                }

                if (value == null)
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401);
                }
                else if (edmProperty.Type.IsEnum())
                {
                    ODataEnumValue enumValue = new ODataEnumValue(value.ToString(), value.GetType().FullName);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V401, model);
                }
                else if (edmProperty.Type.IsDateTimeOffset() && value is DateTime)
                {
                    var dateTime            = (DateTime)value;
                    var dateTimeOffsetValue = TimeZoneInfoHelper.ConvertToDateTimeOffset(dateTime);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(dateTimeOffsetValue, ODataVersion.V401, model);
                }
                else
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401, model);
                }

                var encodedUriLiteral = WebUtility.UrlEncode(uriLiteral);

                skipTokenBuilder.Append(edmProperty.Name).Append(propertyDelimiter).Append(encodedUriLiteral).Append(islast ? String.Empty : CommaDelimiter.ToString());
                count++;
            }

            return(skipTokenBuilder.ToString());
        }
Exemple #52
0
        /// <summary>
        /// Creates the <see cref="ODataEntry"/> to be written while writing this entity.
        /// </summary>
        /// <param name="selectExpandNode">The <see cref="SelectExpandNode"/> describing the response graph.</param>
        /// <param name="entityInstanceContext">The context for the entity instance being written.</param>
        /// <returns>The created <see cref="ODataEntry"/>.</returns>
        public virtual ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
        {
            if (selectExpandNode == null)
            {
                throw Error.ArgumentNull("selectExpandNode");
            }
            if (entityInstanceContext == null)
            {
                throw Error.ArgumentNull("entityInstanceContext");
            }

            string typeName = entityInstanceContext.EntityType.FullName();

            ODataEntry entry = new ODataEntry
            {
                TypeName   = typeName,
                Properties = CreateStructuralPropertyBag(selectExpandNode.SelectedStructuralProperties, entityInstanceContext),
            };

            // Try to add the dynamic properties if the entity type is open.
            if (entityInstanceContext.EntityType.IsOpen && selectExpandNode.SelectAllDynamicProperties)
            {
                IEdmTypeReference entityTypeReference =
                    entityInstanceContext.EntityType.ToEdmTypeReference(isNullable: false);
                List <ODataProperty> dynamicProperties = AppendDynamicProperties(entityInstanceContext.EdmObject,
                                                                                 (IEdmStructuredTypeReference)entityTypeReference,
                                                                                 entityInstanceContext.SerializerContext,
                                                                                 entry.Properties.ToList());

                if (dynamicProperties != null)
                {
                    entry.Properties = entry.Properties.Concat(dynamicProperties);
                }
            }

            IEnumerable <ODataAction> actions = CreateODataActions(selectExpandNode.SelectedActions, entityInstanceContext);

            foreach (ODataAction action in actions)
            {
                entry.AddAction(action);
            }

            IEdmEntityType pathType = GetODataPathType(entityInstanceContext.SerializerContext);

            AddTypeNameAnnotationAsNeeded(entry, pathType, entityInstanceContext.SerializerContext.MetadataLevel);

            if (entityInstanceContext.NavigationSource != null)
            {
                if (!(entityInstanceContext.NavigationSource is IEdmContainedEntitySet))
                {
                    IEdmModel model = entityInstanceContext.SerializerContext.Model;
                    NavigationSourceLinkBuilderAnnotation linkBuilder = model.GetNavigationSourceLinkBuilder(entityInstanceContext.NavigationSource);
                    EntitySelfLinks selfLinks = linkBuilder.BuildEntitySelfLinks(entityInstanceContext, entityInstanceContext.SerializerContext.MetadataLevel);

                    if (selfLinks.IdLink != null)
                    {
                        entry.Id = selfLinks.IdLink;
                    }

                    if (selfLinks.ReadLink != null)
                    {
                        entry.ReadLink = selfLinks.ReadLink;
                    }

                    if (selfLinks.EditLink != null)
                    {
                        entry.EditLink = selfLinks.EditLink;
                    }
                }

                string etag = CreateETag(entityInstanceContext);
                if (etag != null)
                {
                    entry.ETag = etag;
                }
            }

            return(entry);
        }
 public static void EnableHttpDependencyInjectionSupport(this HttpRequestMessage request,
                                                         IEdmModel model)
 {
     request.EnableHttpDependencyInjectionSupport(builder =>
                                                  builder.AddService(ServiceLifetime.Singleton, sp => model));
 }
Exemple #54
0
        /// <summary>
        /// Returns the list of properties that should be used for generating the skiptoken value.
        /// </summary>
        /// <param name="lastMember">The last record that will be returned in the response.</param>
        /// <param name="model">IEdmModel</param>
        /// <param name="orderByNodes">OrderBy nodes in the original request.</param>
        /// <returns>List of properties that should be used for generating the skiptoken value.</returns>
        private static IEnumerable <IEdmProperty> GetPropertiesForSkipToken(object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes)
        {
            IEdmType       edmType = GetTypeFromObject(lastMember, model);
            IEdmEntityType entity  = edmType as IEdmEntityType;

            if (entity == null)
            {
                return(null);
            }

            IEnumerable <IEdmProperty> key = entity.Key();

            if (orderByNodes != null)
            {
                if (orderByNodes.OfType <OrderByOpenPropertyNode>().Any())
                {
                    //SkipToken will not support ordering on dynamic properties
                    return(null);
                }

                IList <IEdmProperty> orderByProps = orderByNodes.OfType <OrderByPropertyNode>().Select(p => p.Property).AsList();
                foreach (IEdmProperty subKey in key)
                {
                    if (!orderByProps.Contains(subKey))
                    {
                        orderByProps.Add(subKey);
                    }
                }

                return(orderByProps.AsEnumerable());
            }

            return(key);
        }
Exemple #55
0
        public static ETag GetETag(this HttpRequest request, EntityTagHeaderValue entityTagHeaderValue)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (entityTagHeaderValue != null)
            {
                if (entityTagHeaderValue.Equals(EntityTagHeaderValue.Any))
                {
                    return(new ETag {
                        IsAny = true
                    });
                }

                // get the etag handler, and parse the etag
                IETagHandler etagHandler = request.GetRequestContainer().GetRequiredService <IETagHandler>();
                IDictionary <string, object> properties = etagHandler.ParseETag(entityTagHeaderValue) ?? new Dictionary <string, object>();
                IList <object> parsedETagValues         = properties.Select(property => property.Value).AsList();

                // get property names from request
                ODataPath            odataPath = request.ODataFeature().Path;
                IEdmModel            model     = request.GetModel();
                IEdmNavigationSource source    = odataPath.NavigationSource;
                if (model != null && source != null)
                {
                    IList <IEdmStructuralProperty> concurrencyProperties = model.GetConcurrencyProperties(source).ToList();
                    IList <string> concurrencyPropertyNames = concurrencyProperties.OrderBy(c => c.Name).Select(c => c.Name).AsList();
                    ETag           etag = new ETag();

                    if (parsedETagValues.Count != concurrencyPropertyNames.Count)
                    {
                        etag.IsWellFormed = false;
                    }

                    IEnumerable <KeyValuePair <string, object> > nameValues = concurrencyPropertyNames.Zip(
                        parsedETagValues,
                        (name, value) => new KeyValuePair <string, object>(name, value));
                    foreach (var nameValue in nameValues)
                    {
                        IEdmStructuralProperty property = concurrencyProperties.SingleOrDefault(e => e.Name == nameValue.Key);
                        Contract.Assert(property != null);

                        Type clrType = EdmLibHelpers.GetClrType(property.Type, model);
                        Contract.Assert(clrType != null);

                        if (nameValue.Value != null)
                        {
                            Type valueType = nameValue.Value.GetType();
                            etag[nameValue.Key] = valueType != clrType
                                ? Convert.ChangeType(nameValue.Value, clrType, CultureInfo.InvariantCulture)
                                : nameValue.Value;
                        }
                        else
                        {
                            etag[nameValue.Key] = nameValue.Value;
                        }
                    }

                    return(etag);
                }
            }

            return(null);
        }
 public static void EnableODataDependencyInjectionSupport(this HttpRequestMessage request, IEdmModel model)
 {
     request.EnableODataDependencyInjectionSupport(HttpRouteCollectionExtensions.RouteName, builder =>
                                                   builder.AddService(ServiceLifetime.Singleton, sp => model));
 }
Exemple #57
0
 private void VerifyParserResult(IEnumerable <XElement> csdl, IEdmModel model)
 {
     CsdlToEdmModelComparer.Compare(csdl, model);
 }
 public static void EnableODataDependencyInjectionSupport(this HttpConfiguration configuration, string routeName,
                                                          IEdmModel model)
 {
     configuration.CreateODataRootContainer(routeName, builder =>
                                            builder.AddService(ServiceLifetime.Singleton, sp => model));
 }
Exemple #59
0
 internal FilterBinder(ODataQuerySettings settings, IWebApiAssembliesResolver assembliesResolver, IEdmModel model)
     : base(model, assembliesResolver, settings)
 {
 }
Exemple #60
0
        public void ExpandedLinkWithMultiplicityTests()
        {
            ODataNestedResourceInfo expandedEntryLink = ObjectModelUtils.CreateDefaultCollectionLink();

            expandedEntryLink.IsCollection = false;

            ODataNestedResourceInfo expandedFeedLink = ObjectModelUtils.CreateDefaultCollectionLink();

            expandedFeedLink.IsCollection = true;

            ODataResource            defaultEntry = ObjectModelUtils.CreateDefaultEntry();
            ODataResourceSet         defaultFeed  = ObjectModelUtils.CreateDefaultFeed();
            ODataEntityReferenceLink defaultEntityReferenceLink = ObjectModelUtils.CreateDefaultEntityReferenceLink();

            ODataResource officeEntry           = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeType");
            ODataResource officeWithNumberEntry = ObjectModelUtils.CreateDefaultEntry("TestModel.OfficeWithNumberType");
            ODataResource cityEntry             = ObjectModelUtils.CreateDefaultEntry("TestModel.CityType");

            // CityHall is a nav prop with multiplicity '*' of type 'TestModel.OfficeType'
            ODataNestedResourceInfo cityHallLinkIsCollectionNull  = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ null);
            ODataNestedResourceInfo cityHallLinkIsCollectionTrue  = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ true);
            ODataNestedResourceInfo cityHallLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("CityHall", /*isCollection*/ false);

            // PoliceStation is a nav prop with multiplicity '1' of type 'TestModel.OfficeType'
            ODataNestedResourceInfo policeStationLinkIsCollectionNull  = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ null);
            ODataNestedResourceInfo policeStationLinkIsCollectionTrue  = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ true);
            ODataNestedResourceInfo policeStationLinkIsCollectionFalse = ObjectModelUtils.CreateDefaultCollectionLink("PoliceStation", /*isCollection*/ false);

            ExpectedException expandedEntryLinkWithFeedContentError  = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetContent", "http://odata.org/link");
            ExpectedException expandedFeedLinkWithEntryContentError  = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceContent", "http://odata.org/link");
            ExpectedException expandedFeedLinkWithEntryMetadataError = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceMetadata", "http://odata.org/link");

            ExpectedException expandedEntryLinkWithFeedMetadataErrorResponse        = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetMetadata", "http://odata.org/link");
            ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorRequest  = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithResourceSetPayloadAndResourceMetadata", "http://odata.org/link");
            ExpectedException expandedFeedLinkPayloadWithEntryMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionTrueWithResourceMetadata", "http://odata.org/link");
            ExpectedException expandedEntryLinkPayloadWithFeedMetadataErrorResponse = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkIsCollectionFalseWithResourceSetMetadata", "http://odata.org/link");
            ExpectedException expandedEntryLinkPayloadWithFeedMetadataError         = ODataExpectedExceptions.ODataException("WriterValidationUtils_ExpandedLinkWithResourcePayloadAndResourceSetMetadata", "http://odata.org/link");
            ExpectedException multipleItemsInExpandedLinkError   = ODataExpectedExceptions.ODataException("ODataWriterCore_MultipleItemsInNestedResourceInfoWithContent", "http://odata.org/link");
            ExpectedException entityReferenceLinkInResponseError = ODataExpectedExceptions.ODataException("ODataWriterCore_EntityReferenceLinkInResponse");

            IEdmModel model = Microsoft.Test.OData.Utils.Metadata.TestModels.BuildTestModel();

            var testCases = new ExpandedLinkMultiplicityTestCase[]
            {
                #region IsCollection flag does not match payload
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link with IsCollection is 'false' and feed payload
                    Items         = new ODataItem[] { defaultEntry, expandedEntryLink, defaultFeed },
                    ExpectedError = tc => expandedEntryLinkWithFeedContentError,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link with IsCollection is 'true' and entry payload
                    Items         = new ODataItem[] { defaultEntry, expandedFeedLink, defaultEntry },
                    ExpectedError = tc => expandedFeedLinkWithEntryContentError,
                },
                #endregion IsCollection flag does not match payload
                #region IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of singleton type without IsCollection value and an entry of a non-matching entity type;
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, cityEntry },
                    ExpectedError = tc => !tc.IsRequest
                            ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceTypeNotCompatibleWithParentPropertyType", "TestModel.CityType", "TestModel.OfficeType")
                            : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "PoliceStation"),
                    Model = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of singleton type without IsCollection value and an entry of a matching entity type; no error expected.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry },
                    ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "PoliceStation"),
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of singleton type without IsCollection and an entry of a derived entity type; no error expected.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeWithNumberEntry },
                    ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest ? null : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "PoliceStation"),
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of collection type without IsCollection value and an entry of a non-matching entity type;
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, cityEntry },
                    ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest
                            ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceTypeNotCompatibleWithParentPropertyType", "TestModel.CityType", "TestModel.OfficeType")
                            : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "CityHall"),
                    Model = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of collection type without IsCollection value and an entry of a matching entity type; no error expected.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry },
                    ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest
                            ? null
                            : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "CityHall"),
                    Model = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Expanded link of collection type without IsCollection and an entry of a derived entity type; no error expected.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeWithNumberEntry },
                    ExpectedError = tc => tc.Format == ODataFormat.Json && !tc.IsRequest
                            ? null
                            : ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "CityHall"),
                    Model = model,
                },
                #endregion IsCollection == null; check compatibility of entity types of navigation property and entity in expanded link
                #region Expanded link with entry content
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == false, singleton nav prop; should not fail.
                    Items = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, officeEntry },
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == true, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, officeEntry },
                    ExpectedError = tc => expandedFeedLinkWithEntryContentError,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == false, collection nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, officeEntry },
                    ExpectedError = tc => tc.IsRequest ? expandedEntryLinkPayloadWithFeedMetadataError : expandedEntryLinkPayloadWithFeedMetadataErrorResponse,
                    Model         = model
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == true, collection nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, officeEntry },
                    ExpectedError = tc => expandedFeedLinkWithEntryContentError,
                    Model         = model
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == null, singleton nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, officeEntry },
                    ExpectedError = tc => tc.IsRequest
                            ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "PoliceStation")
                            : null,
                    Model = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Entry content, IsCollection == null, collection nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, officeEntry },
                    ExpectedError = tc => expandedEntryLinkPayloadWithFeedMetadataError,
                    Model         = model,
                },
                #endregion Expanded collection link with entry content
                #region Expanded link with feed content
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == false, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultFeed, officeEntry },
                    ExpectedError = tc => expandedEntryLinkWithFeedContentError,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == true, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultFeed, officeEntry },
                    ExpectedError = tc => tc.IsRequest ? expandedFeedLinkPayloadWithEntryMetadataErrorRequest : expandedFeedLinkPayloadWithEntryMetadataErrorResponse,
                    Model         = model
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == false, collection nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultFeed, officeEntry },
                    ExpectedError = tc => tc.IsRequest ? expandedEntryLinkWithFeedContentError : expandedEntryLinkWithFeedMetadataErrorResponse,
                    Model         = model
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == true, collection nav prop; should not fail.
                    Items = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultFeed, officeEntry },
                    Model = model
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == null, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionNull, defaultFeed, officeEntry },
                    ExpectedError = tc => expandedFeedLinkPayloadWithEntryMetadataErrorRequest,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Feed content, IsCollection == null, collection nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionNull, defaultFeed, officeEntry },
                    ExpectedError = tc => tc.IsRequest
                            ? ODataExpectedExceptions.ODataException("WriterValidationUtils_NestedResourceInfoMustSpecifyIsCollection", "CityHall")
                            : null,
                    Model = model,
                },
                #endregion Expanded collection link with entry content
                #region Expanded link with entity reference link content
                new ExpandedLinkMultiplicityTestCase
                {
                    // Single ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Multiple ERL (entity reference link) content, IsCollection == false, singleton nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : entityReferenceLinkInResponseError,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Single ERL content, IsCollection == true, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink },
                    ExpectedError = tc => expandedFeedLinkWithEntryMetadataError,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Multiple ERL content, IsCollection == true, singleton nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, policeStationLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink },
                    ExpectedError = tc => expandedFeedLinkWithEntryMetadataError,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Single ERL content, IsCollection == false, collection nav prop; should not fail (metadata mismatch explicitly allowed).
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? null : expandedEntryLinkWithFeedMetadataErrorResponse,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Multiple ERL content, IsCollection == false, collection nav prop; should fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionFalse, defaultEntityReferenceLink, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? multipleItemsInExpandedLinkError : expandedEntryLinkWithFeedMetadataErrorResponse,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Single ERL content, IsCollection == true, collection nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError,
                    Model         = model,
                },
                new ExpandedLinkMultiplicityTestCase
                {
                    // Multiple ERL content, IsCollection == true, collection nav prop; should not fail.
                    Items         = new ODataItem[] { cityEntry, cityHallLinkIsCollectionTrue, defaultEntityReferenceLink, defaultEntityReferenceLink },
                    ExpectedError = tc => tc.IsRequest ? null : entityReferenceLinkInResponseError,
                    Model         = model,
                },

                //// NOTE: Not testing the cases where IsCollection == null here since ERL payloads are only allowed in
                ////       requests where IsCollection is required (in ATOM and JSON)
                #endregion Expanded link with entity reference link content
            };

            // TODO: Fix places where we've lost JsonVerbose coverage to add JsonLight
            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(tc => false),
                (testCase, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                using (var memoryStream = new TestStream())
                    using (var messageWriter = TestWriterUtils.CreateMessageWriter(memoryStream, testConfiguration, this.Assert, null, testCase.Model))
                    {
                        ODataWriter writer = messageWriter.CreateODataWriter(isFeed: false);
                        TestExceptionUtils.ExpectedException(
                            this.Assert,
                            () => TestWriterUtils.WritePayload(messageWriter, writer, true, testCase.Items),
                            testCase.ExpectedError == null ? null : testCase.ExpectedError(testConfiguration),
                            this.ExceptionVerifier);
                    }
            });
        }