示例#1
0
        private bool SerializeWithoutCyclicLoop(IEnumerable collection, string format, IFormatProvider formatProvider, StringBuilder builder, bool withoutFormat,
                                                SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (objectsInPath.Contains(collection))
            {
                return(false); // detected reference loop, skip serialization
            }
            if (depth > MaxRecursionDepth)
            {
                return(false); // reached maximum recursion level, no further serialization
            }

            IDictionary dictionary = collection as IDictionary;

            if (dictionary != null)
            {
                using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(dictionary, ref objectsInPath, true))
                {
                    return(SerializeDictionaryObject(dictionary, format, formatProvider, builder, withoutFormat, objectsInPath, depth));
                }
            }

            using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(collection, ref objectsInPath, true))
            {
                return(SerializeCollectionObject(collection, format, formatProvider, builder, withoutFormat, objectsInPath, depth));
            }
        }
示例#2
0
        private bool SerializeObjectProperties(ObjectReflectionCache.ObjectPropertyList objectPropertyList, StringBuilder destination, JsonSerializeOptions options,
                                               SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            destination.Append('{');

            bool first = true;

            foreach (var propertyValue in objectPropertyList)
            {
                var originalLength = destination.Length;

                try
                {
                    if (HasNameAndValue(propertyValue))
                    {
                        if (!first)
                        {
                            destination.Append(", ");
                        }

                        if (options.QuoteKeys)
                        {
                            QuoteValue(destination, propertyValue.Name);
                        }
                        else
                        {
                            destination.Append(propertyValue.Name);
                        }
                        destination.Append(':');

                        var objTypeCode = propertyValue.TypeCode;
                        if (objTypeCode != TypeCode.Object)
                        {
                            SerializeSimpleTypeCodeValue((IConvertible)propertyValue.Value, objTypeCode, destination, options);
                            first = false;
                        }
                        else
                        {
                            if (!SerializeObject(propertyValue.Value, destination, options, objectsInPath, depth + 1))
                            {
                                destination.Length = originalLength;
                            }
                            else
                            {
                                first = false;
                            }
                        }
                    }
                }
                catch
                {
                    // skip single property
                    destination.Length = originalLength;
                }
            }

            destination.Append('}');
            return(true);
        }
示例#3
0
        /// <summary>
        /// Serialization of the object in JSON format to the destination StringBuilder
        /// </summary>
        /// <param name="value">The object to serialize to JSON.</param>
        /// <param name="destination">Write the resulting JSON to this destination.</param>
        /// <param name="options">serialisation options</param>
        /// <param name="objectsInPath">The objects in path (Avoid cyclic reference loop).</param>
        /// <param name="depth">The current depth (level) of recursion.</param>
        /// <returns>Object serialized succesfully (true/false).</returns>
        private bool SerializeObject(object value, StringBuilder destination, JsonSerializeOptions options,
                                     SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (objectsInPath.Contains(value))
            {
                return(false); // detected reference loop, skip serialization
            }
            if (depth > MaxRecursionDepth)
            {
                return(false); // reached maximum recursion level, no further serialization
            }

            if (value == null)
            {
                destination.Append("null");
            }
            else if (value is string str)
            {
                QuoteValue(destination, EscapeString(str, options.EscapeUnicode));
            }
            else if (value is IDictionary dict)
            {
                using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(dict, ref objectsInPath, true))
                {
                    SerializeDictionaryObject(dict, destination, options, objectsInPath, depth);
                }
            }
            else if (value is IEnumerable enumerable)
            {
                using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, true))
                {
                    SerializeCollectionObject(enumerable, destination, options, objectsInPath, depth);
                }
            }
            else
            {
                var format    = options.Format;
                var hasFormat = !StringHelpers.IsNullOrWhiteSpace(format);
                if ((options.FormatProvider != null || hasFormat) && (value is IFormattable formattable))
                {
                    if (!SerializeWithFormatProvider(value, destination, options, formattable, format, hasFormat))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!SerializeTypeCodeValue(value, destination, options, objectsInPath, depth))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
示例#4
0
        private bool SerializeObjectProperties(ObjectReflectionCache.ObjectPropertyList objectPropertyList, StringBuilder destination, JsonSerializeOptions options,
                                               SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (objectPropertyList.Count == 0)
            {
                //no props
                return(SerializeObjectAsString(objectPropertyList.ToString(), TypeCode.Object, destination, options));
            }

            destination.Append('{');

            bool first = true;

            foreach (var propertyValue in objectPropertyList)
            {
                var originalLength = destination.Length;

                try
                {
                    if (HasNameAndValue(propertyValue))
                    {
                        if (!first)
                        {
                            destination.Append(", ");
                        }

                        if (options.QuoteKeys)
                        {
                            QuoteValue(destination, propertyValue.Name);
                        }
                        else
                        {
                            destination.Append(propertyValue.Name);
                        }
                        destination.Append(':');

                        if (!SerializeObject(propertyValue.Value, propertyValue.TypeCode, destination, options, objectsInPath, depth + 1))
                        {
                            destination.Length = originalLength;
                        }
                        else
                        {
                            first = false;
                        }
                    }
                }
                catch
                {
                    //skip this property
                    destination.Length = originalLength;
                }
            }

            destination.Append('}');
            return(true);
        }
示例#5
0
        /// <summary>
        /// Serialization of the object in JSON format to the destination StringBuilder
        /// </summary>
        /// <param name="value">The object to serialize to JSON.</param>
        /// <param name="destination">Write the resulting JSON to this destination.</param>
        /// <param name="options">serialisation options</param>
        /// <param name="objectsInPath">The objects in path (Avoid cyclic reference loop).</param>
        /// <param name="depth">The current depth (level) of recursion.</param>
        /// <returns>Object serialized succesfully (true/false).</returns>
        private bool SerializeObject(object value, StringBuilder destination, JsonSerializeOptions options,
                                     SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (objectsInPath.Contains(value))
            {
                return(false); // detected reference loop, skip serialization
            }

            if (value == null)
            {
                destination.Append("null");
            }
            else if (value is string str)
            {
                destination.Append('"');
                AppendStringEscape(destination, str, options.EscapeUnicode);
                destination.Append('"');
            }
            else if (value is IDictionary dict)
            {
                using (StartScope(ref objectsInPath, dict))
                {
                    SerializeDictionaryObject(dict, destination, options, objectsInPath, depth);
                }
            }
            else if (value is IEnumerable enumerable)
            {
                using (StartScope(ref objectsInPath, value))
                {
                    SerializeCollectionObject(enumerable, destination, options, objectsInPath, depth);
                }
            }
            else
            {
                var format    = options.Format;
                var hasFormat = !StringHelpers.IsNullOrWhiteSpace(format);
                if ((options.FormatProvider != null || hasFormat) && (value is IFormattable formattable))
                {
                    if (!SerializeWithFormatProvider(value, destination, options, formattable, format, hasFormat))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!SerializeTypeCodeValue(value, destination, options, objectsInPath, depth))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
示例#6
0
        /// <summary>
        /// Serialization of the object in JSON format to the destination StringBuilder
        /// </summary>
        /// <param name="value">The object to serialize to JSON.</param>
        /// <param name="objTypeCode">The TypeCode for the object to serialize.</param>
        /// <param name="destination">Write the resulting JSON to this destination.</param>
        /// <param name="options">serialisation options</param>
        /// <param name="objectsInPath">The objects in path (Avoid cyclic reference loop).</param>
        /// <param name="depth">The current depth (level) of recursion.</param>
        /// <returns>Object serialized succesfully (true/false).</returns>
        private bool SerializeObject(object value, TypeCode objTypeCode, StringBuilder destination, JsonSerializeOptions options,
                                     SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (objTypeCode == TypeCode.Object && objectsInPath.Contains(value))
            {
                return(false); // detected reference loop, skip serialization
            }

            if (value == null)
            {
                destination.Append("null");
            }
            else if (objTypeCode == TypeCode.String)
            {
                destination.Append('"');
                AppendStringEscape(destination, value.ToString(), options.EscapeUnicode);
                destination.Append('"');
            }
            else if (objTypeCode != TypeCode.Object)
            {
                return(SerializeWithTypeCode(value, objTypeCode, destination, options, ref objectsInPath, depth));
            }
            else if (value is IDictionary dict)
            {
                using (StartCollectionScope(ref objectsInPath, dict))
                {
                    SerializeDictionaryObject(dict, destination, options, objectsInPath, depth);
                }
            }
            else if (value is IDictionary <string, object> expando)
            {
                // Special case for Expando-objects
                using (StartCollectionScope(ref objectsInPath, expando))
                {
                    return(SerializeObjectProperties(new ObjectReflectionCache.ObjectPropertyList(expando), destination, options, objectsInPath, depth));
                }
            }
            else if (value is IEnumerable enumerable)
            {
                using (StartCollectionScope(ref objectsInPath, value))
                {
                    SerializeCollectionObject(enumerable, destination, options, objectsInPath, depth);
                }
            }
            else
            {
                return(SerializeWithTypeCode(value, objTypeCode, destination, options, ref objectsInPath, depth));
            }
            return(true);
        }
示例#7
0
        /// <summary>
        /// Serialization of the object in JSON format to the destination StringBuilder
        /// </summary>
        /// <param name="value">The object to serialize to JSON.</param>
        /// <param name="destination">Write the resulting JSON to this destination.</param>
        /// <param name="options">serialisation options</param>
        /// <param name="objectsInPath">The objects in path (Avoid cyclic reference loop).</param>
        /// <param name="depth">The current depth (level) of recursion.</param>
        /// <returns>Object serialized successfully (true/false).</returns>
        private bool SerializeObject(object value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            int originalLength = destination.Length;

            try
            {
                if (SerializeSimpleObjectValue(value, destination, options))
                {
                    return(true);
                }

                return(SerializeObjectWithReflection(value, destination, options, ref objectsInPath, depth));
            }
            catch
            {
                destination.Length = originalLength;
                return(false);
            }
        }
        private bool SerializeProperties(object value, StringBuilder destination, JsonSerializeOptions options,
                                         SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            var props = GetProps(value);

            if (props.Key.Length == 0)
            {
                try
                {
                    //no props
                    QuoteValue(destination, EscapeString(Convert.ToString(value, CultureInfo.InvariantCulture), options.EscapeUnicode));
                    return(true);
                }
                catch
                {
                    return(false);
                }
            }

            destination.Append('{');

            bool first               = true;
            int  originalLength      = 0;
            bool useLateBoundMethods = props.Key.Length == props.Value.Length;

            for (var i = 0; i < props.Key.Length; i++)
            {
                originalLength = destination.Length;

                try
                {
                    var prop      = props.Key[i];
                    var propValue = useLateBoundMethods ? props.Value[i](value, null) : prop.GetValue(value, null);
                    if (propValue != null)
                    {
                        if (!first)
                        {
                            destination.Append(", ");
                        }

                        if (options.QuoteKeys)
                        {
                            QuoteValue(destination, prop.Name);
                        }
                        else
                        {
                            destination.Append(prop.Name);
                        }
                        destination.Append(':');

                        if (!SerializeObject(propValue, destination, options, objectsInPath, depth + 1))
                        {
                            destination.Length = originalLength;
                        }
                        else
                        {
                            first = false;
                        }
                    }
                }
                catch
                {
                    //skip this property
                    destination.Length = originalLength;
                }
            }

            destination.Append('}');
            return(true);
        }
        private bool SerializeTypeCodeValue(object value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            TypeCode objTypeCode = Convert.GetTypeCode(value);

            if (objTypeCode == TypeCode.Object)
            {
                if (value is Guid || value is TimeSpan)
                {
                    //object without property, to string
                    QuoteValue(destination, Convert.ToString(value, CultureInfo.InvariantCulture));
                }
                else if (value is DateTimeOffset)
                {
                    QuoteValue(destination, string.Format("{0:yyyy-MM-dd HH:mm:ss zzz}", value));
                }
                else
                {
                    int originalLength = destination.Length;
                    try
                    {
                        using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, false))
                        {
                            return(SerializeProperties(value, destination, options, objectsInPath, depth));
                        }
                    }
                    catch
                    {
                        //nothing to add, so return is OK
                        destination.Length = originalLength;
                        return(false);
                    }
                }
            }
            else
            {
                if (IsNumericTypeCode(objTypeCode, false))
                {
                    Enum enumValue;
                    if (!options.EnumAsInteger && (enumValue = value as Enum) != null)
                    {
                        QuoteValue(destination, EnumAsString(enumValue));
                    }
                    else
                    {
                        AppendIntegerAsString(destination, value, objTypeCode);
                    }
                }
                else
                {
                    string str = XmlHelper.XmlConvertToString(value, objTypeCode);
                    if (str == null)
                    {
                        return(false);
                    }
                    if (SkipQuotes(objTypeCode))
                    {
                        destination.Append(str);
                    }
                    else
                    {
                        QuoteValue(destination, str);
                    }
                }
            }

            return(true);
        }
示例#10
0
        private void SerializeCollectionObject(IEnumerable value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool first = true;

            int originalLength;

            destination.Append('[');
            foreach (var val in value)
            {
                originalLength = destination.Length;
                if (!first)
                {
                    destination.Append(',');
                }

                if (!SerializeObject(val, destination, options, objectsInPath, depth + 1))
                {
                    destination.Length = originalLength;
                }
                else
                {
                    first = false;
                }
            }
            destination.Append(']');
        }
示例#11
0
        private void SerializeDictionaryObject(IDictionary value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool first = true;

            int originalLength;

            destination.Append('{');
            foreach (DictionaryEntry de in value)
            {
                originalLength = destination.Length;
                if (!first)
                {
                    destination.Append(',');
                }

                //only serialize, if key and value are serialized without error (e.g. due to reference loop)
                if (!SerializeObject(de.Key, destination, options, objectsInPath, depth + 1))
                {
                    destination.Length = originalLength;
                }
                else
                {
                    destination.Append(':');
                    if (!SerializeObject(de.Value, destination, options, objectsInPath, depth + 1))
                    {
                        destination.Length = originalLength;
                    }
                    else
                    {
                        first = false;
                    }
                }
            }
            destination.Append('}');
        }
示例#12
0
        private bool SerializeDictionaryObject(IDictionary dictionary, string format, IFormatProvider formatProvider, StringBuilder builder, bool withoutFormat, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool separator = false;

            foreach (DictionaryEntry item in dictionary)
            {
                if (builder.Length > MaxValueLength)
                {
                    return(false);
                }

                if (separator)
                {
                    builder.Append(", ");
                }

                if (item.Key is string || !(item.Key is IEnumerable))
                {
                    SerializeObject(item.Key, format, formatProvider, builder);
                }
                else
                {
                    SerializeWithoutCyclicLoop((IEnumerable)item.Key, format, formatProvider, builder, withoutFormat, objectsInPath, depth + 1);
                }
                builder.Append("=");
                if (item.Value is string || !(item.Value is IEnumerable))
                {
                    SerializeObject(item.Value, format, formatProvider, builder);
                }
                else
                {
                    SerializeWithoutCyclicLoop((IEnumerable)item.Value, format, formatProvider, builder, withoutFormat, objectsInPath, depth + 1);
                }
                separator = true;
            }
            return(true);
        }
示例#13
0
        private void SerializeDictionaryObject(IDictionary dictionary, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool first = true;

            int nextDepth = objectsInPath.Count <= 1 ? depth : (depth + 1);

            if (nextDepth > options.MaxRecursionLimit)
            {
                destination.Append("{}");
                return;
            }

            destination.Append('{');
            foreach (var item in new DictionaryEntryEnumerable(dictionary))
            {
                var originalLength = destination.Length;
                if (originalLength > MaxJsonLength)
                {
                    break;
                }

                if (!first)
                {
                    destination.Append(',');
                }

                var itemKey = item.Key;
                if (options.QuoteKeys)
                {
                    if (!SerializeObjectAsString(itemKey, destination, options))
                    {
                        destination.Length = originalLength;
                        continue;
                    }
                }
                else
                {
                    if (!SerializeObject(itemKey, destination, options, objectsInPath, nextDepth))
                    {
                        destination.Length = originalLength;
                        continue;
                    }
                }

                if (options.SanitizeDictionaryKeys)
                {
                    int quoteSkipCount = options.QuoteKeys ? 1 : 0;
                    int keyEndIndex    = destination.Length - quoteSkipCount;
                    int keyStartIndex  = originalLength + (first ? 0 : 1) + quoteSkipCount;
                    if (!SanitizeDictionaryKey(destination, keyStartIndex, keyEndIndex - keyStartIndex))
                    {
                        destination.Length = originalLength;    // Empty keys are not allowed
                        continue;
                    }
                }

                destination.Append(':');

                //only serialize, if key and value are serialized without error (e.g. due to reference loop)
                var itemValue = item.Value;
                if (!SerializeObject(itemValue, destination, options, objectsInPath, nextDepth))
                {
                    destination.Length = originalLength;
                }
                else
                {
                    first = false;
                }
            }
            destination.Append('}');
        }
示例#14
0
        private bool SerializeObjectWithProperties(object value, StringBuilder destination, JsonSerializeOptions options, ref SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            if (depth < options.MaxRecursionLimit)
            {
                var objectPropertyList = _objectReflectionCache.LookupObjectProperties(value);
                if (!objectPropertyList.ConvertToString)
                {
                    if (ReferenceEquals(options, Instance._serializeOptions) && value is Exception)
                    {
                        // Exceptions are seldom under control, and can include random Data-Dictionary-keys, so we sanitize by default
                        options = Instance._exceptionSerializeOptions;
                    }

                    using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, false, _referenceEqualsComparer))
                    {
                        return(SerializeObjectProperties(objectPropertyList, destination, options, objectsInPath, depth));
                    }
                }
            }

            return(SerializeObjectAsString(value, destination, options));
        }
示例#15
0
        private bool SerializeTypeCodeValue(object value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            TypeCode objTypeCode = Convert.GetTypeCode(value);

            if (objTypeCode == TypeCode.Object)
            {
                if (value is Guid || value is TimeSpan || value is MemberInfo || value is Assembly)
                {
                    //object without property, to string
                    QuoteValue(destination, Convert.ToString(value, CultureInfo.InvariantCulture));
                }
                else if (value is DateTimeOffset)
                {
                    QuoteValue(destination, $"{value:yyyy-MM-dd HH:mm:ss zzz}");
                }
                else
                {
                    int originalLength = destination.Length;
                    if (originalLength > MaxJsonLength)
                    {
                        return(false);
                    }

                    if (depth < options.MaxRecursionLimit)
                    {
                        try
                        {
                            if (value is Exception && ReferenceEquals(options, instance._serializeOptions))
                            {
                                // Exceptions are seldom under control, and can include random Data-Dictionary-keys, so we sanitize by default
                                options = instance._exceptionSerializeOptions;
                            }

                            using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, false))
                            {
                                return(SerializeProperties(value, destination, options, objectsInPath, depth));
                            }
                        }
                        catch
                        {
                            //nothing to add, so return is OK
                            destination.Length = originalLength;
                            return(false);
                        }
                    }
                    else
                    {
                        try
                        {
                            string str = Convert.ToString(value, CultureInfo.InvariantCulture);
                            destination.Append('"');
                            AppendStringEscape(destination, str, options.EscapeUnicode);
                            destination.Append('"');
                        }
                        catch
                        {
                            return(false);
                        }
                    }
                }
            }
            else
            {
                if (IsNumericTypeCode(objTypeCode, false))
                {
                    SerializeNumber(value, destination, options, objTypeCode);
                }
                else
                {
                    string str = XmlHelper.XmlConvertToString(value, objTypeCode);
                    if (str == null)
                    {
                        return(false);
                    }
                    if (SkipQuotes(objTypeCode))
                    {
                        destination.Append(str);
                    }
                    else
                    {
                        QuoteValue(destination, str);
                    }
                }
            }

            return(true);
        }
示例#16
0
 private void SerializeCollectionItem(object item, string format, IFormatProvider formatProvider, StringBuilder builder, ref SingleItemOptimizedHashSet <object> objectsInPath, int depth)
 {
     if (item is IConvertible convertible)
     {
         SerializeConvertibleObject(convertible, format, formatProvider, builder);
     }
     else if (item is IEnumerable enumerable)
     {
         SerializeWithoutCyclicLoop(enumerable, format, formatProvider, builder, objectsInPath, depth + 1);
     }
     else
     {
         SerializeSimpleObject(item, format, formatProvider, builder);
     }
 }
示例#17
0
        private bool SerializeWithTypeCode(object value, TypeCode objTypeCode, StringBuilder destination, JsonSerializeOptions options, ref SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            var hasFormat = !StringHelpers.IsNullOrWhiteSpace(options.Format);

            if ((options.FormatProvider != null || hasFormat) && (value is IFormattable formattable))
            {
                return(SerializeWithFormatProvider(value, objTypeCode, destination, options, formattable, options.Format, hasFormat));
            }
            else
            {
                if (objTypeCode == TypeCode.Object)
                {
                    if (value is DateTimeOffset)
                    {
                        QuoteValue(destination, $"{value:yyyy-MM-dd HH:mm:ss zzz}");
                        return(true);
                    }
                    else
                    {
                        return(SerializeObjectWithProperties(value, destination, options, ref objectsInPath, depth));
                    }
                }
                else
                {
                    return(SerializeSimpleTypeCodeValue(value, objTypeCode, destination, options));
                }
            }
        }
示例#18
0
        private bool SerializeCollectionObject(IEnumerable collection, string format, IFormatProvider formatProvider, StringBuilder builder, bool withoutFormat, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool separator = false;

            foreach (var item in collection)
            {
                if (builder.Length > MaxValueLength)
                {
                    return(false);
                }

                if (separator)
                {
                    builder.Append(", ");
                }

                if (item is string || !(item is IEnumerable))
                {
                    SerializeObject(item, format, formatProvider, builder);
                }
                else
                {
                    SerializeWithoutCyclicLoop((IEnumerable)item, format, formatProvider, builder, withoutFormat, objectsInPath, depth + 1);
                }

                separator = true;
            }
            return(true);
        }
示例#19
0
        private bool SerializeObjectWithReflection(object value, StringBuilder destination, JsonSerializeOptions options, ref SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            int originalLength = destination.Length;

            if (originalLength > MaxJsonLength)
            {
                return(false);
            }

            if (objectsInPath.Contains(value))
            {
                return(false);
            }

            if (value is IDictionary dict)
            {
                using (StartCollectionScope(ref objectsInPath, dict))
                {
                    SerializeDictionaryObject(dict, destination, options, objectsInPath, depth);
                    return(true);
                }
            }

            if (value is IEnumerable enumerable)
            {
                if (_objectReflectionCache.TryLookupExpandoObject(value, out var propertyValues))
                {
                    if (propertyValues.ConvertToString || depth >= options.MaxRecursionLimit)
                    {
                        return(SerializeObjectAsString(value, destination, options));
                    }
                    else
                    {
                        using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, false, _referenceEqualsComparer))
                        {
                            return(SerializeObjectProperties(propertyValues, destination, options, objectsInPath, depth));
                        }
                    }
                }

                using (StartCollectionScope(ref objectsInPath, value))
                {
                    SerializeCollectionObject(enumerable, destination, options, objectsInPath, depth);
                    return(true);
                }
            }
            else
            {
                return(SerializeObjectWithProperties(value, destination, options, ref objectsInPath, depth));
            }
        }
示例#20
0
        private bool SerializeCollectionObject(IEnumerable collection, string format, IFormatProvider formatProvider, StringBuilder builder, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool separator = false;

            foreach (var item in collection)
            {
                if (builder.Length > MaxValueLength)
                {
                    return(false);
                }

                if (separator)
                {
                    builder.Append(", ");
                }

                SerializeCollectionItem(item, format, formatProvider, builder, ref objectsInPath, depth);

                separator = true;
            }
            return(true);
        }
示例#21
0
 private static SingleItemOptimizedHashSet <object> .SingleItemScopedInsert StartCollectionScope(ref SingleItemOptimizedHashSet <object> objectsInPath, object value)
 {
     return(new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, true, _referenceEqualsComparer));
 }
示例#22
0
        private bool SerializeObjectWithProperties(object value, StringBuilder destination, JsonSerializeOptions options, ref SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            int originalLength = destination.Length;

            if (originalLength > MaxJsonLength)
            {
                return(false);
            }

            if (depth < options.MaxRecursionLimit)
            {
                try
                {
                    if (value is Exception && ReferenceEquals(options, instance._serializeOptions))
                    {
                        // Exceptions are seldom under control, and can include random Data-Dictionary-keys, so we sanitize by default
                        options = instance._exceptionSerializeOptions;
                    }

                    using (new SingleItemOptimizedHashSet <object> .SingleItemScopedInsert(value, ref objectsInPath, false, _referenceEqualsComparer))
                    {
                        return(SerializeProperties(value, destination, options, objectsInPath, depth));
                    }
                }
                catch
                {
                    //nothing to add, so return is OK
                    destination.Length = originalLength;
                    return(false);
                }
            }
            else
            {
                return(SerializeObjectAsString(value, TypeCode.Object, destination, options));
            }
        }
示例#23
0
        private void SerializeCollectionObject(IEnumerable value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool first = true;

            int nextDepth = objectsInPath.Count <= 1 ? depth : (depth + 1); // Allow serialization of list-items

            if (nextDepth > options.MaxRecursionLimit)
            {
                destination.Append("[]");
                return;
            }

            int originalLength;

            destination.Append('[');
            foreach (var val in value)
            {
                originalLength = destination.Length;
                if (originalLength > MaxJsonLength)
                {
                    break;
                }

                if (!first)
                {
                    destination.Append(',');
                }

                if (!SerializeObject(val, destination, options, objectsInPath, nextDepth))
                {
                    destination.Length = originalLength;
                }
                else
                {
                    first = false;
                }
            }
            destination.Append(']');
        }
示例#24
0
        private void SerializeDictionaryObject(IDictionary value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool first = true;

            int originalLength;

            destination.Append('{');
            foreach (DictionaryEntry de in value)
            {
                originalLength = destination.Length;
                if (originalLength > MaxJsonLength)
                {
                    break;
                }

                if (!first)
                {
                    destination.Append(',');
                }

                //only serialize, if key and value are serialized without error (e.g. due to reference loop)
                if (!SerializeObject(de.Key, destination, options, objectsInPath, depth + 1))
                {
                    destination.Length = originalLength;
                }
                else
                {
                    if (options.SanitizeDictionaryKeys)
                    {
                        int quoteSkipCount = options.QuoteKeys ? 1 : 0;
                        int keyEndIndex    = destination.Length - quoteSkipCount;
                        int keyStartIndex  = originalLength + (first ? 0 : 1) + quoteSkipCount;
                        if (!SanitizeDictionaryKey(destination, keyStartIndex, keyEndIndex - keyStartIndex))
                        {
                            destination.Length = originalLength;    // Empty keys are not allowed
                            continue;
                        }
                    }

                    destination.Append(':');
                    if (!SerializeObject(de.Value, destination, options, objectsInPath, depth + 1))
                    {
                        destination.Length = originalLength;
                    }
                    else
                    {
                        first = false;
                    }
                }
            }
            destination.Append('}');
        }
示例#25
0
        private bool SerializeTypeCodeValue(object value, StringBuilder destination, JsonSerializeOptions options, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            TypeCode objTypeCode = Convert.GetTypeCode(value);

            if (objTypeCode == TypeCode.Object)
            {
                if (value is Guid || value is TimeSpan || value is MemberInfo || value is Assembly)
                {
                    //object without property, to string
                    QuoteValue(destination, Convert.ToString(value, CultureInfo.InvariantCulture));
                    return(true);
                }
                else if (value is DateTimeOffset)
                {
                    QuoteValue(destination, $"{value:yyyy-MM-dd HH:mm:ss zzz}");
                    return(true);
                }
                else
                {
                    return(SerializeObjectWithProperties(value, destination, options, ref objectsInPath, depth));
                }
            }
            else
            {
                return(SerializeSimpleTypeCodeValue(value, objTypeCode, destination, options));
            }
        }
示例#26
0
        /// <summary>
        /// Serialize Dictionary as JSON like structure, without { and }
        /// </summary>
        /// <example>
        /// "FirstOrder"=true, "Previous login"=20-12-2017 14:55:32, "number of tries"=1
        /// </example>
        /// <param name="dictionary"></param>
        /// <param name="format">formatstring of an item</param>
        /// <param name="formatProvider"></param>
        /// <param name="builder"></param>
        /// <param name="objectsInPath"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        private bool SerializeDictionaryObject(IDictionary dictionary, string format, IFormatProvider formatProvider, StringBuilder builder, SingleItemOptimizedHashSet <object> objectsInPath, int depth)
        {
            bool separator = false;

            foreach (var item in new DictionaryEntryEnumerable(dictionary))
            {
                if (builder.Length > MaxValueLength)
                {
                    return(false);
                }

                if (separator)
                {
                    builder.Append(", ");
                }

                SerializeCollectionItem(item.Key, format, formatProvider, builder, ref objectsInPath, depth);
                builder.Append("=");
                SerializeCollectionItem(item.Value, format, formatProvider, builder, ref objectsInPath, depth);
                separator = true;
            }
            return(true);
        }