/// <summary> /// Adds an OData annotation to a property. /// </summary> /// <param name="propertyName">The name of the property to add annotation to. string.empty means the annotation is for the current scope.</param> /// <param name="annotationName">The name of the annotation to add.</param> /// <param name="annotationValue">The valud of the annotation to add.</param> internal void AddODataPropertyAnnotation(string propertyName, string annotationName, object annotationValue) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)"); Debug.Assert(JsonLight.ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName), "annotationName must be an OData annotation."); DuplicationRecord duplicationRecord = this.GetDuplicationRecordToAddPropertyAnnotation(propertyName, annotationName); Dictionary <string, object> odataAnnotations = duplicationRecord.PropertyODataAnnotations; if (odataAnnotations == null) { odataAnnotations = new Dictionary <string, object>(StringComparer.Ordinal); duplicationRecord.PropertyODataAnnotations = odataAnnotations; } else if (odataAnnotations.ContainsKey(annotationName)) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationForInstanceAnnotationNotAllowed(annotationName, propertyName)); } throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(annotationName, propertyName)); } odataAnnotations.Add(annotationName, annotationValue); }
/// <summary> /// Throw if property is processed already. /// </summary> /// <param name="propertyName">Name of the property.</param> /// <param name="duplicationRecord">DuplicationRecord of the property.</param> private static void ThrowIfPropertyIsProcessed(string propertyName, DuplicationRecord duplicationRecord) { if (object.ReferenceEquals(duplicationRecord.PropertyODataAnnotations, propertyAnnotationsProcessedToken)) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName) && !ODataJsonLightUtils.IsMetadataReferenceProperty(propertyName)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed(propertyName)); } throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed(propertyName)); } }
/// <summary> /// Marks a property to note that all its annotations should have been processed by now. /// </summary> /// <param name="propertyName">Name of the property.</param> /// <remarks> /// It's an error if more annotations for a marked property are found later in the payload. /// </remarks> internal void MarkPropertyAsProcessed(string propertyName) { Debug.Assert(propertyName != null); PropertyData data; if (!propertyData.TryGetValue(propertyName, out data)) { propertyData[propertyName] = data = new PropertyData(PropertyState.AnnotationSeen); } if (data.Processed) { throw new ODataException( ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName) && !ODataJsonLightUtils.IsMetadataReferenceProperty(propertyName) ? Strings.DuplicateAnnotationNotAllowed(propertyName) : Strings.DuplicatePropertyNamesNotAllowed(propertyName)); } data.Processed = true; }
/// <summary> /// Adds an OData property annotation. /// </summary> /// <param name="propertyName">Name of the property.</param> /// <param name="annotationName">Name of the annotation.</param> /// <param name="annotationValue">Value of the annotation.</param> internal void AddODataPropertyAnnotation(string propertyName, string annotationName, object annotationValue) { Debug.Assert(!string.IsNullOrEmpty(propertyName)); Debug.Assert(!string.IsNullOrEmpty(annotationName)); Debug.Assert(JsonLight.ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName)); if (annotationValue == null) { return; } PropertyData data; if (!propertyData.TryGetValue(propertyName, out data)) { propertyData[propertyName] = data = new PropertyData(PropertyState.AnnotationSeen); } else { if (data.Processed) { throw new ODataException( Strings.PropertyAnnotationAfterTheProperty( annotationName, propertyName)); } } try { data.ODataAnnotations.Add(annotationName, annotationValue); } catch (ArgumentException) { throw new ODataException( ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName) ? Strings.DuplicateAnnotationForInstanceAnnotationNotAllowed(annotationName, propertyName) : Strings.DuplicateAnnotationForPropertyNotAllowed(annotationName, propertyName)); } }
/// <summary> /// Try to read an inner error property value. /// </summary> /// <param name="innerError">An <see cref="ODataInnerError"/> instance that was read from the reader or null if none could be read.</param> /// <param name="recursionDepth">The number of times this method has been called recursively.</param> /// <returns>true if an <see cref="ODataInnerError"/> instance that was read; otherwise false.</returns> private bool TryReadInnerErrorPropertyValue(out ODataInnerError innerError, int recursionDepth) { Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.Property, "this.currentBufferedNode.NodeType == JsonNodeType.Property"); Debug.Assert(this.parsingInStreamError, "this.parsingInStreamError"); this.AssertBuffering(); ValidationUtils.IncreaseAndValidateRecursionDepth(ref recursionDepth, this.maxInnerErrorDepth); // move the reader onto the property value this.ReadInternal(); // we expect a start-object node here if (this.currentBufferedNode.NodeType != JsonNodeType.StartObject) { innerError = null; return(false); } // read the start-object node this.ReadInternal(); innerError = new ODataInnerError(); // we expect one of the supported properties for the value (or end-object) ODataJsonLightReaderUtils.ErrorPropertyBitMask propertiesFoundBitmask = ODataJsonLightReaderUtils.ErrorPropertyBitMask.None; while (this.currentBufferedNode.NodeType == JsonNodeType.Property) { // NOTE the Json reader already ensures that the value of a property node is a string string propertyName = (string)this.currentBufferedNode.Value; switch (propertyName) { case JsonConstants.ODataErrorInnerErrorMessageName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.MessageValue)) { return(false); } string message; if (this.TryReadErrorStringPropertyValue(out message)) { innerError.Message = message; } else { return(false); } break; case JsonConstants.ODataErrorInnerErrorTypeNameName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.TypeName)) { return(false); } string typeName; if (this.TryReadErrorStringPropertyValue(out typeName)) { innerError.TypeName = typeName; } else { return(false); } break; case JsonConstants.ODataErrorInnerErrorStackTraceName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.StackTrace)) { return(false); } string stackTrace; if (this.TryReadErrorStringPropertyValue(out stackTrace)) { innerError.StackTrace = stackTrace; } else { return(false); } break; case JsonConstants.ODataErrorInnerErrorInnerErrorName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.InnerError)) { return(false); } ODataInnerError nestedInnerError; if (this.TryReadInnerErrorPropertyValue(out nestedInnerError, recursionDepth)) { innerError.InnerError = nestedInnerError; } else { return(false); } break; default: // if we find a non-supported property in an inner error, we skip it this.SkipValueInternal(); break; } this.ReadInternal(); } Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.EndObject, "this.currentBufferedNode.NodeType == JsonNodeType.EndObject"); return(true); }
private bool TryReadErrorDetail(out ODataErrorDetail detail) { Debug.Assert( this.currentBufferedNode.NodeType == JsonNodeType.StartObject, "this.currentBufferedNode.NodeType == JsonNodeType.StartObject"); Debug.Assert(this.parsingInStreamError, "this.parsingInStreamError"); this.AssertBuffering(); if (this.currentBufferedNode.NodeType != JsonNodeType.StartObject) { detail = null; return(false); } // { ReadInternal(); detail = new ODataErrorDetail(); // we expect one of the supported properties for the value (or end-object) var propertiesFoundBitmask = ODataJsonLightReaderUtils.ErrorPropertyBitMask.None; while (this.currentBufferedNode.NodeType == JsonNodeType.Property) { var propertyName = (string)this.currentBufferedNode.Value; switch (propertyName) { case JsonConstants.ODataErrorCodeName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound( ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Code)) { return(false); } string code; if (this.TryReadErrorStringPropertyValue(out code)) { detail.ErrorCode = code; } else { return(false); } break; case JsonConstants.ODataErrorTargetName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound( ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Target)) { return(false); } string target; if (this.TryReadErrorStringPropertyValue(out target)) { detail.Target = target; } else { return(false); } break; case JsonConstants.ODataErrorMessageName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound( ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.MessageValue)) { return(false); } string message; if (this.TryReadErrorStringPropertyValue(out message)) { detail.Message = message; } else { return(false); } break; default: // if we find a non-supported property in an inner error, we skip it this.SkipValueInternal(); break; } this.ReadInternal(); } Debug.Assert( this.currentBufferedNode.NodeType == JsonNodeType.EndObject, "this.currentBufferedNode.NodeType == JsonNodeType.EndObject"); return(true); }
/// <summary> /// Try to read an error structure from the stream. Return null if no error structure can be read. /// </summary> /// <param name="error">An <see cref="ODataError"/> instance that was read from the reader or null if none could be read.</param> /// <returns>true if an <see cref="ODataError"/> instance that was read; otherwise false.</returns> private bool TryReadInStreamErrorPropertyValue(out ODataError error) { Debug.Assert(this.parsingInStreamError, "this.parsingInStreamError"); this.AssertBuffering(); error = null; // we expect a start-object node here if (this.currentBufferedNode.NodeType != JsonNodeType.StartObject) { return(false); } // read the start-object node this.ReadInternal(); error = new ODataError(); // we expect one of the supported properties for the value (or end-object) ODataJsonLightReaderUtils.ErrorPropertyBitMask propertiesFoundBitmask = ODataJsonLightReaderUtils.ErrorPropertyBitMask.None; while (this.currentBufferedNode.NodeType == JsonNodeType.Property) { // NOTE the Json reader already ensures that the value of a property node is a string string propertyName = (string)this.currentBufferedNode.Value; switch (propertyName) { case JsonConstants.ODataErrorCodeName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Code)) { return(false); } string errorCode; if (this.TryReadErrorStringPropertyValue(out errorCode)) { error.ErrorCode = errorCode; } else { return(false); } break; case JsonConstants.ODataErrorMessageName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Message)) { return(false); } string errorMessage; if (this.TryReadErrorStringPropertyValue(out errorMessage)) { error.Message = errorMessage; } else { return(false); } break; case JsonConstants.ODataErrorTargetName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound( ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Target)) { return(false); } string errorTarget; if (this.TryReadErrorStringPropertyValue(out errorTarget)) { error.Target = errorTarget; } else { return(false); } break; case JsonConstants.ODataErrorDetailsName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound( ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.Details)) { return(false); } ICollection <ODataErrorDetail> details; if (!this.TryReadErrorDetailsPropertyValue(out details)) { return(false); } error.Details = details; break; case JsonConstants.ODataErrorInnerErrorName: if (!ODataJsonLightReaderUtils.ErrorPropertyNotFound(ref propertiesFoundBitmask, ODataJsonLightReaderUtils.ErrorPropertyBitMask.InnerError)) { return(false); } ODataInnerError innerError; if (!this.TryReadInnerErrorPropertyValue(out innerError, 0 /*recursionDepth */)) { return(false); } error.InnerError = innerError; break; default: // if we find a non-supported property we don't treat this as an error return(false); } this.ReadInternal(); } // read the end object Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.EndObject, "this.currentBufferedNode.NodeType == JsonNodeType.EndObject"); this.ReadInternal(); // if we don't find any properties it is not a valid error object return(propertiesFoundBitmask != ODataJsonLightReaderUtils.ErrorPropertyBitMask.None); }