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; }
/// <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); } } }
private static IEnumerable <ODataInputFormatter> CreateInputFormatters(IEdmModel model = null) { // Model is not used in AspNetCore. return(ODataInputFormatterFactory.Create()); }
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); } } }
public OeQueryExpression(IEdmModel edmModel, IEdmEntitySet entitySet, Expression expression) { EdmModel = edmModel; _entitySet = entitySet; _expression = new OeEnumerableToQuerableVisitor().Visit(expression); }
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); } }
private void ValidateFilterInExpand(IEdmProperty property, IEdmStructuredType structuredType, IEdmModel edmModel, FilterClause filterClause, ODataValidationSettings validationSettings) { if (filterClause != null) { _filterQueryValidator.Validate(property, structuredType, filterClause, validationSettings, edmModel, _defaultQuerySettings); } }
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()); }
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"); }
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(); } }
public static Type GetClrType(IEdmType edmType, IEdmModel edmModel) { return(GetClrType(edmType, edmModel, _defaultAssemblyResolver)); }
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"); }
public static bool IsNotCountable(IEdmProperty edmProperty, IEdmModel edmModel) { QueryableRestrictionsAnnotation annotation = GetPropertyRestrictions(edmProperty, edmModel); return(annotation == null ? false : annotation.Restrictions.NotCountable); }
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=\""etag1"\" 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); }); }
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); } }
/// <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()); }
/// <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)); }
/// <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); }
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)); }
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)); }
internal FilterBinder(ODataQuerySettings settings, IWebApiAssembliesResolver assembliesResolver, IEdmModel model) : base(model, assembliesResolver, settings) { }
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); } }); }