示例#1
0
        /// <summary> Clones the specified options, but omits the specified converters, if present. </summary>
        public static JsonSerializerOptions CloneWithout(this JsonSerializerOptions options, params JsonConverter[] convertersToRemove)
        {
            Contract.Requires(options != null);
            Contract.Requires(convertersToRemove != null);

            var result = options.Clone();

            foreach (var converterToRemove in convertersToRemove)
            {
                result.Converters.Remove(converterToRemove);
            }
            return(result);
        }
        /// <inheritdoc />
        public override IAuditLogChange Read
        (
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options
        )
        {
            using var jsonDocument = JsonDocument.ParseValue(ref reader);
            if (!jsonDocument.RootElement.TryGetProperty("key", out var keyProperty))
            {
                throw new JsonException();
            }

            var key = keyProperty.GetString();

            if (key is null)
            {
                throw new JsonException();
            }

            if (!KeyTypes.TryGetValue(key, out var valueType))
            {
                throw new JsonException();
            }

            if (KeyConverters.TryGetValue(key, out var keyConverter))
            {
                options = options.Clone();
                options.Converters.Add(keyConverter);
            }

            Optional <object> newValue = default;
            Optional <object> oldValue = default;

            if (jsonDocument.RootElement.TryGetProperty("old_value", out var oldValueProperty))
            {
                var value = JsonSerializer.Deserialize(oldValueProperty.GetRawText(), valueType, options);
                oldValue = value;
            }

            // ReSharper disable once InvertIf
            if (jsonDocument.RootElement.TryGetProperty("new_value", out var newValueProperty))
            {
                var value = JsonSerializer.Deserialize(newValueProperty.GetRawText(), valueType, options);
                newValue = value;
            }

            return(new AuditLogChange(newValue, oldValue, key));
        }
        JsonSerializerOptions?GetJsonSerializerSettings(IJsonSerializationOptions?options = null)
        {
            if (options == null)
            {
                return(null);
            }

            var o = _options.Clone();

            o.IgnoreNullValues     = options.OmitNull ?? o.IgnoreNullValues;
            o.WriteIndented        = options.Indent ?? o.WriteIndented;
            o.DictionaryKeyPolicy  = options.CamelCaseKeys == true ? JsonNamingPolicy.CamelCase : o.DictionaryKeyPolicy;
            o.PropertyNamingPolicy = options.CamelCaseProperties == true ? JsonNamingPolicy.CamelCase : o.PropertyNamingPolicy;
            return(o);
        }
示例#4
0
        /// <inheritdoc />
        public override void Write
        (
            Utf8JsonWriter writer,
            TInterface value,
            JsonSerializerOptions options
        )
        {
            writer.WriteStartObject();

            foreach (var dtoProperty in _dtoProperties)
            {
                var propertyGetter = dtoProperty.GetGetMethod();
                if (propertyGetter is null)
                {
                    continue;
                }

                var propertyValue = propertyGetter.Invoke(value, new object?[] { });

                if (propertyValue is IOptional optional && !optional.HasValue)
                {
                    continue;
                }

                var jsonName = GetWriteJsonPropertyName(dtoProperty, options);
                writer.WritePropertyName(jsonName);

                var propertyType = dtoProperty.PropertyType;
                var converter    = GetConverter(dtoProperty, options);
                if (converter is null)
                {
                    JsonSerializer.Serialize(writer, propertyValue, propertyType, options);
                }
                else
                {
                    // This converter should only be in effect for the duration of this property; we'll need to clone
                    // the options.
                    var clonedOptions = options.Clone();
                    clonedOptions.Converters.Add(converter);

                    JsonSerializer.Serialize(writer, propertyValue, propertyType, clonedOptions);
                }
            }

            writer.WriteEndObject();
        }
        /// <inheritdoc />
        public override TInterface Read
        (
            ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options
        )
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }

            if (!reader.Read())
            {
                throw new JsonException();
            }

            var readProperties = new Dictionary <PropertyInfo, object?>();

            while (reader.TokenType != JsonTokenType.EndObject)
            {
                var propertyName = reader.GetString();
                if (!reader.Read())
                {
                    throw new JsonException();
                }

                var isPrimaryChoice = true;

                // Search for a property that has this JSON property's name as its primary option
                var dtoProperty = _dtoProperties.FirstOrDefault
                                  (
                    p => GetReadJsonPropertyName(p, options)[0] == propertyName
                                  );

                if (dtoProperty is null)
                {
                    // Allow the fallbacks to be searched as well, but mark it as just an alternative
                    dtoProperty = _dtoProperties.FirstOrDefault
                                  (
                        p => GetReadJsonPropertyName(p, options).Contains(propertyName)
                                  );

                    if (dtoProperty is not null)
                    {
                        isPrimaryChoice = false;
                    }
                }

                if (dtoProperty is null)
                {
                    if (!_allowExtraProperties)
                    {
                        throw new JsonException();
                    }

                    // No matching property - we'll skip it
                    if (!reader.TrySkip())
                    {
                        throw new JsonException("Couldn't skip elements.");
                    }

                    if (!reader.Read())
                    {
                        throw new JsonException
                              (
                                  $"No matching DTO property for JSON property \"{propertyName}\" could be found."
                              );
                    }

                    continue;
                }

                var propertyType = dtoProperty.PropertyType;

                var converter = GetConverter(dtoProperty, options);

                object?propertyValue;
                if (converter is null)
                {
                    propertyValue = JsonSerializer.Deserialize(ref reader, propertyType, options);
                }
                else
                {
                    // This converter should only be in effect for the duration of this property; we'll need to clone
                    // the options.
                    var clonedOptions = options.Clone();
                    clonedOptions.Converters.Add(converter);

                    propertyValue = JsonSerializer.Deserialize(ref reader, propertyType, clonedOptions);
                }

                // Verify nullability
                if (!dtoProperty.AllowsNull() && propertyValue is null)
                {
                    throw new JsonException();
                }

                if (!readProperties.ContainsKey(dtoProperty))
                {
                    readProperties.Add(dtoProperty, propertyValue);
                }
                else if (isPrimaryChoice)
                {
                    readProperties[dtoProperty] = propertyValue;
                }

                if (!reader.Read())
                {
                    throw new JsonException();
                }
            }

            // Reorder and polyfill the read properties
            var constructorArguments = new object?[_dtoProperties.Count];

            for (var i = 0; i < _dtoProperties.Count; i++)
            {
                var dtoProperty = _dtoProperties[i];
                if (!readProperties.TryGetValue(dtoProperty, out var propertyValue))
                {
                    if (dtoProperty.PropertyType.IsOptional())
                    {
                        propertyValue = Activator.CreateInstance(dtoProperty.PropertyType);
                    }
                    else
                    {
                        throw new InvalidOperationException
                              (
                                  $"The data property \"{dtoProperty.Name}\" did not have a corresponding value in the JSON."
                              );
                    }
                }

                constructorArguments[i] = propertyValue;
            }

            return((TInterface)_dtoConstructor.Invoke(constructorArguments));
        }
 public JsonSerializerFactory(JsonSerializerOptions?defaultOptions)
 {
     _options = defaultOptions?.Clone() ?? DefaultOptions;
 }