/// <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> /// <param name="writerValidator">The writer validator to use for validation.</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, IWriterValidator writerValidator) { 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)); } writerValidator.ValidateTypeKind(resolvedType.TypeKind, expectedTypeKind, resolvedType); return resolvedType; }
/// <summary> /// Constructor. /// </summary> /// <param name="outputContext">The output context to write to.</param> protected ODataSerializer(ODataOutputContext outputContext) { Debug.Assert(outputContext != null, "outputContext != null"); this.outputContext = outputContext; this.WriterValidator = outputContext.WriterValidator; }
/// <summary> /// Constructs a <see cref="JsonLightInstanceAnnotationWriter"/> that can write a collection of <see cref="ODataInstanceAnnotation"/>. /// </summary> /// <param name="valueSerializer">The <see cref="IODataJsonLightValueSerializer"/> to use for writing values of instance annotations. /// The <see cref="IJsonWriter"/> that is also used internally will be acquired from the this instance.</param> /// <param name="typeNameOracle">The oracle to use to determine the type name to write for entries and values.</param> internal JsonLightInstanceAnnotationWriter(IODataJsonLightValueSerializer valueSerializer, JsonLightTypeNameOracle typeNameOracle) { Debug.Assert(valueSerializer != null, "valueSerializer should not be null"); this.valueSerializer = valueSerializer; this.typeNameOracle = typeNameOracle; this.jsonWriter = this.valueSerializer.JsonWriter; this.odataAnnotationWriter = new JsonLightODataAnnotationWriter(this.jsonWriter, valueSerializer.Settings.ODataSimplified); this.writerValidator = ValidatorFactory.CreateWriterValidator(this.valueSerializer.Settings.EnableFullValidation); }
/// <summary> /// Constructs a <see cref="JsonLightInstanceAnnotationWriter"/> that can write a collection of <see cref="ODataInstanceAnnotation"/>. /// </summary> /// <param name="valueSerializer">The <see cref="ODataJsonLightValueSerializer"/> to use for writing values of instance annotations. /// The <see cref="IJsonWriter"/> that is also used internally will be acquired from the this instance.</param> /// <param name="typeNameOracle">The oracle to use to determine the type name to write for entries and values.</param> internal JsonLightInstanceAnnotationWriter(ODataJsonLightValueSerializer valueSerializer, JsonLightTypeNameOracle typeNameOracle) { Debug.Assert(valueSerializer != null, "valueSerializer should not be null"); this.valueSerializer = valueSerializer; this.typeNameOracle = typeNameOracle; this.jsonWriter = this.valueSerializer.JsonWriter; this.odataAnnotationWriter = new JsonLightODataAnnotationWriter(this.jsonWriter, valueSerializer.JsonLightOutputContext.ODataSimplifiedOptions.EnableWritingODataAnnotationWithoutPrefix, this.valueSerializer.MessageWriterSettings.Version); this.writerValidator = this.valueSerializer.MessageWriterSettings.Validator; }
public static IWriterValidator CreateWriterValidator(bool enableFullValidation) { if (enableFullValidation) { return fullWriterValidator ?? (fullWriterValidator = new WriterValidatorFullValidation()); } else { return minimalWriterValidator ?? (minimalWriterValidator = new WriterValidatorMinimalValidation()); } }
public static IWriterValidator CreateWriterValidator(bool enableFullValidation) { if (enableFullValidation) { return(fullWriterValidator ?? (fullWriterValidator = new WriterValidatorFullValidation())); } else { return(minimalWriterValidator ?? (minimalWriterValidator = new WriterValidatorMinimalValidation())); } }
/// <summary> /// Constructs a <see cref="JsonLightInstanceAnnotationWriter"/> that can write a collection of <see cref="ODataInstanceAnnotation"/>. /// </summary> /// <param name="valueSerializer">The <see cref="ODataJsonLightValueSerializer"/> to use for writing values of instance annotations. /// The <see cref="IJsonWriter"/> that is also used internally will be acquired from the this instance.</param> /// <param name="typeNameOracle">The oracle to use to determine the type name to write for entries and values.</param> internal JsonLightInstanceAnnotationWriter(ODataJsonLightValueSerializer valueSerializer, JsonLightTypeNameOracle typeNameOracle) { Debug.Assert(valueSerializer != null, "valueSerializer should not be null"); this.valueSerializer = valueSerializer; this.typeNameOracle = typeNameOracle; this.jsonWriter = this.valueSerializer.JsonWriter; this.odataAnnotationWriter = this.valueSerializer.ODataAnnotationWriter; this.asynchronousJsonWriter = this.valueSerializer.AsynchronousJsonWriter; this.asynchronousODataAnnotationWriter = this.valueSerializer.AsynchronousODataAnnotationWriter; this.writerValidator = this.valueSerializer.MessageWriterSettings.Validator; }
/// <summary> /// Constructor. /// </summary> /// <param name="format">The format for this output context.</param> /// <param name="messageInfo">The context information for the message.</param> /// <param name="messageWriterSettings">Configuration settings of the OData writer.</param> protected ODataOutputContext( ODataFormat format, ODataMessageInfo messageInfo, ODataMessageWriterSettings messageWriterSettings) { ExceptionUtils.CheckArgumentNotNull(format, "format"); ExceptionUtils.CheckArgumentNotNull(messageWriterSettings, "messageWriterSettings"); this.format = format; this.messageWriterSettings = messageWriterSettings; this.writingResponse = messageInfo.IsResponse; this.synchronous = !messageInfo.IsAsync; this.model = messageInfo.Model ?? EdmCoreModel.Instance; this.payloadUriConverter = messageInfo.PayloadUriConverter; this.container = messageInfo.Container; this.edmTypeResolver = EdmTypeWriterResolver.Instance; this.payloadValueConverter = ODataPayloadValueConverter.GetPayloadValueConverter(this.container); this.writerValidator = messageWriterSettings.Validator; this.odataSimplifiedOptions = ODataSimplifiedOptions.GetODataSimplifiedOptions(this.container, messageWriterSettings.Version); }
/// <summary> /// Constructor. /// </summary> /// <param name="format">The format for this output context.</param> /// <param name="messageWriterSettings">Configuration settings of the OData writer.</param> /// <param name="writingResponse">true if writing a response message; otherwise false.</param> /// <param name="synchronous">true if the output should be written synchronously; false if it should be written asynchronously.</param> /// <param name="model">The model to use.</param> /// <param name="urlResolver">The optional URL resolver to perform custom URL resolution for URLs written to the payload.</param> protected ODataOutputContext( ODataFormat format, ODataMessageWriterSettings messageWriterSettings, bool writingResponse, bool synchronous, IEdmModel model, IODataUrlResolver urlResolver) { ExceptionUtils.CheckArgumentNotNull(format, "format"); ExceptionUtils.CheckArgumentNotNull(messageWriterSettings, "messageWriterSettings"); this.format = format; this.messageWriterSettings = messageWriterSettings; this.writingResponse = writingResponse; this.synchronous = synchronous; this.model = model ?? EdmCoreModel.Instance; this.urlResolver = urlResolver; this.edmTypeResolver = EdmTypeWriterResolver.Instance; this.payloadValueConverter = this.model.GetPayloadValueConverter(); this.writerValidator = ValidatorFactory.CreateWriterValidator(messageWriterSettings.EnableFullValidation); }
/// <summary> /// Constructor. /// </summary> /// <param name="outputContext">The output context to write to.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="writingFeed">True if the writer is created for writing a feed; false when it is created for writing an entry.</param> /// <param name="writingDelta">True if the writer is created for writing a delta response; false otherwise.</param> /// <param name="listener">If not null, the writer will notify the implementer of the interface of relevant state changes in the writer.</param> protected ODataWriterCore( ODataOutputContext outputContext, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool writingFeed, bool writingDelta = false, IODataReaderWriterListener listener = null) { Debug.Assert(outputContext != null, "outputContext != null"); Debug.Assert(!writingDelta || outputContext.WritingResponse, "writingResponse must be true when writingDelta is true"); this.outputContext = outputContext; this.writingFeed = writingFeed; this.writingDelta = writingDelta; this.WriterValidator = outputContext.WriterValidator; // create a collection validator when writing a top-level feed and a user model is present if (this.writingFeed && this.outputContext.Model.IsUserModel()) { this.feedValidator = new FeedWithoutExpectedTypeValidator(); } if (navigationSource != null && entityType == null) { entityType = this.outputContext.EdmTypeResolver.GetElementType(navigationSource); } ODataUri odataUri = outputContext.MessageWriterSettings.ODataUri.Clone(); // Remove key for top level entry if (!writingFeed && odataUri != null && odataUri.Path != null) { odataUri.Path = odataUri.Path.TrimEndingKeySegment(); } this.listener = listener; this.scopes.Push(new Scope(WriterState.Start, /*item*/null, navigationSource, entityType, /*skipWriting*/false, outputContext.MessageWriterSettings.SelectedProperties, odataUri)); }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="complexValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="complexValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForComplexValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataComplexValue complexValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); var typeName = complexValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Complex, writerValidator); if (typeReferenceFromMetadata != null) { writerValidator.ValidateTypeKind(EdmTypeKind.Complex, typeReferenceFromMetadata.TypeKind(), typeFromValue); } IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator); return(typeReferenceFromValue); }
/// <summary> /// Resolve a resource type name /// </summary> /// <param name="model">The model to use.</param> /// <param name="expectedType">The type inferred from the model or null if the model is not a user model.</param> /// <param name="typeName">Name of the type to resolve.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for primitive value</returns> internal static IEdmStructuredType ResolveAndValidateTypeFromTypeName(IEdmModel model, IEdmStructuredType expectedType, string typeName, IWriterValidator writerValidator) { if (typeName == null && expectedType != null) { return(expectedType); } // TODO: Clean up handling of expected types/sets during writing IEdmType typeFromResource = ResolveAndValidateTypeName(model, typeName, EdmTypeKind.None, /* expectStructuredType */ true, writerValidator); IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue( expectedType.ToTypeReference(), typeFromResource == null ? null : typeFromResource.ToTypeReference(), writerValidator); if (typeReferenceFromValue != null && typeReferenceFromValue.IsUntyped()) { return(new EdmUntypedStructuredType()); } return(typeReferenceFromValue == null ? null : typeReferenceFromValue.ToStructuredType()); }
/// <summary> /// Validates that the (optional) <paramref name="typeReferenceFromMetadata"/> is the same as the (optional) <paramref name="typeReferenceFromValue"/>. /// </summary> /// <param name="typeReferenceFromMetadata">The (optional) type from the metadata definition (the expected type).</param> /// <param name="typeReferenceFromValue">The (optional) type from the value (the actual type).</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>The type as derived from the <paramref name="typeReferenceFromMetadata"/> and/or <paramref name="typeReferenceFromValue"/>.</returns> private static IEdmTypeReference ResolveTypeFromMetadataAndValue(IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, IWriterValidator writerValidator) { if (typeReferenceFromMetadata == null) { // if we have no metadata information there is nothing to validate return(typeReferenceFromValue); } if (typeReferenceFromValue == null) { // derive the property type from the metadata return(typeReferenceFromMetadata); } Debug.Assert(typeReferenceFromValue.TypeKind() == typeReferenceFromMetadata.TypeKind(), "typeReferenceFromValue.TypeKind() == typeReferenceFromMetadata.TypeKind()"); writerValidator.ValidateTypeReference(typeReferenceFromMetadata, typeReferenceFromValue); return(typeReferenceFromValue); }
/// <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> /// <param name="expectStructuredType">This value indicates if a structured type is expected to be return. /// True for structured type, false for non-structured type, null for indetermination.</param> /// <param name="writerValidator">The writer validator to use for validation.</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, bool?expectStructuredType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); Debug.Assert( !expectStructuredType.HasValue || !expectStructuredType.Value && !expectedTypeKind.IsStructured() || expectStructuredType.Value && (expectedTypeKind.IsStructured() || expectedTypeKind == EdmTypeKind.None), "!expectStructuredType.HasValue || !expectStructuredType.Value && !expectedTypeKind.IsStructured() || expectStructuredType.Value && (expectedTypeKind.IsStructured() || expectedTypeKind == EdmTypeKind.None)"); if (typeName == null) { // if we have metadata, the type name of a resource 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)); } if (resolvedType.TypeKind != EdmTypeKind.Untyped) { writerValidator.ValidateTypeKind(resolvedType.TypeKind, expectedTypeKind, expectStructuredType, resolvedType); } return(resolvedType); }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="collectionValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="collectionValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForCollectionValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataCollectionValue collectionValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); var typeName = collectionValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Collection, false, writerValidator); if (typeReferenceFromMetadata != null) { writerValidator.ValidateTypeKind(EdmTypeKind.Collection, typeReferenceFromMetadata.TypeKind(), false, typeFromValue); } IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator); if (typeReferenceFromValue != null) { // update nullability from metadata if (typeReferenceFromMetadata != null) { typeReferenceFromValue = typeReferenceFromMetadata; } // validate that the collection type represents a valid Collection type (e.g., is unordered). typeReferenceFromValue = ValidationUtils.ValidateCollectionType(typeReferenceFromValue); } return(typeReferenceFromValue); }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="resourceValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open (dynamic) property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="resourceValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForResourceValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataResourceValue resourceValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); Debug.Assert(resourceValue != null, "resourceValue != null"); var typeName = resourceValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); // It's ok to use "EdmTypeKind.Complex" because the validation will check "IsStructured()". IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Complex, true, writerValidator); if (typeReferenceFromMetadata != null) { // It's ok to use "EdmTypeKind.Complex" because the parameter "expectStructuredType" is set to "true". writerValidator.ValidateTypeKind(EdmTypeKind.Complex, typeReferenceFromMetadata.TypeKind(), true, typeFromValue); } return(ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator)); }
/// <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> /// <param name="writerValidator">The writer validator to use for validation.</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, IWriterValidator writerValidator) { 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)); } writerValidator.ValidateTypeKind(resolvedType.TypeKind, expectedTypeKind, resolvedType); return(resolvedType); }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="complexValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="complexValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForComplexValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataComplexValue complexValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); var typeName = complexValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Complex, writerValidator); if (typeReferenceFromMetadata != null) { writerValidator.ValidateTypeKind(EdmTypeKind.Complex, typeReferenceFromMetadata.TypeKind(), typeFromValue); } IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator); return typeReferenceFromValue; }
/// <summary> /// Validates that the (optional) <paramref name="typeReferenceFromMetadata"/> is the same as the (optional) <paramref name="typeReferenceFromValue"/>. /// </summary> /// <param name="typeReferenceFromMetadata">The (optional) type from the metadata definition (the expected type).</param> /// <param name="typeReferenceFromValue">The (optional) type from the value (the actual type).</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>The type as derived from the <paramref name="typeReferenceFromMetadata"/> and/or <paramref name="typeReferenceFromValue"/>.</returns> private static IEdmTypeReference ResolveTypeFromMetadataAndValue(IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, IWriterValidator writerValidator) { if (typeReferenceFromMetadata == null) { // if we have no metadata information there is nothing to validate return typeReferenceFromValue; } if (typeReferenceFromValue == null) { // derive the property type from the metadata return typeReferenceFromMetadata; } Debug.Assert(typeReferenceFromValue.TypeKind() == typeReferenceFromMetadata.TypeKind(), "typeReferenceFromValue.TypeKind() == typeReferenceFromMetadata.TypeKind()"); writerValidator.ValidateTypeReference(typeReferenceFromMetadata, typeReferenceFromValue); return typeReferenceFromValue; }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="collectionValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="collectionValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForCollectionValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataCollectionValue collectionValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); var typeName = collectionValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Collection, writerValidator); if (typeReferenceFromMetadata != null) { writerValidator.ValidateTypeKind(EdmTypeKind.Collection, typeReferenceFromMetadata.TypeKind(), typeFromValue); } IEdmTypeReference typeReferenceFromValue = ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator); if (typeReferenceFromValue != null) { // update nullability from metadata if (typeReferenceFromMetadata != null) { typeReferenceFromValue = typeReferenceFromMetadata; } // validate that the collection type represents a valid Collection type (e.g., is unordered). typeReferenceFromValue = writerValidator.ValidateCollectionType(typeReferenceFromValue); } return typeReferenceFromValue; }