sql >> データベース >  >> NoSQL >> MongoDB

サブプロパティのJSON.NETカスタム名前リゾルバー

    問題のプロパティに対して、カスタム<コードを作成することができます。> JsonConverter 別の JsonSerializer> 次のように、別のコントラクトリゾルバで作成されます:

    public class AlternateContractResolverConverter : JsonConverter
    {
        [ThreadStatic]
        static Stack<Type> contractResolverTypeStack;
    
        static Stack<Type> ContractResolverTypeStack { get { return contractResolverTypeStack = (contractResolverTypeStack ?? new Stack<Type>()); } }
    
        readonly IContractResolver resolver;
    
        JsonSerializerSettings ExtractAndOverrideSettings(JsonSerializer serializer)
        {
            var settings = serializer.ExtractSettings();
            settings.ContractResolver = resolver;
            settings.CheckAdditionalContent = false;
            if (settings.PreserveReferencesHandling != PreserveReferencesHandling.None)
            {
                // Log an error throw an exception?
                Debug.WriteLine(string.Format("PreserveReferencesHandling.{0} not supported", serializer.PreserveReferencesHandling));
            }
            return settings;
        }
    
        public AlternateContractResolverConverter(Type resolverType)
        {
            if (resolverType == null)
                throw new ArgumentNullException("resolverType");
            resolver = (IContractResolver)Activator.CreateInstance(resolverType);
            if (resolver == null)
                throw new ArgumentNullException(string.Format("Resolver type {0} not found", resolverType));
        }
    
        public override bool CanRead { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }
        public override bool CanWrite { get { return ContractResolverTypeStack.Count == 0 || ContractResolverTypeStack.Peek() != resolver.GetType(); } }
    
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException("This contract resolver is intended to be applied directly with [JsonConverter(typeof(AlternateContractResolverConverter), typeof(SomeContractResolver))] or [JsonProperty(ItemConverterType = typeof(AlternateContractResolverConverter), ItemConverterParameters = ...)]");
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
                return JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Deserialize(reader, objectType);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            using (ContractResolverTypeStack.PushUsing(resolver.GetType()))
                JsonSerializer.CreateDefault(ExtractAndOverrideSettings(serializer)).Serialize(writer, value);
        }
    }
    
    internal static class JsonSerializerExtensions
    {
        public static JsonSerializerSettings ExtractSettings(this JsonSerializer serializer)
        {
            // There is no built-in API to extract the settings from a JsonSerializer back into JsonSerializerSettings,
            // so we have to fake it here.
            if (serializer == null)
                throw new ArgumentNullException("serializer");
            var settings = new JsonSerializerSettings
            {
                CheckAdditionalContent = serializer.CheckAdditionalContent,
                ConstructorHandling = serializer.ConstructorHandling,
                ContractResolver = serializer.ContractResolver,
                Converters = serializer.Converters,
                Context = serializer.Context,
                Culture = serializer.Culture,
                DateFormatHandling = serializer.DateFormatHandling,
                DateFormatString = serializer.DateFormatString,
                DateParseHandling = serializer.DateParseHandling,
                DateTimeZoneHandling = serializer.DateTimeZoneHandling,
                DefaultValueHandling = serializer.DefaultValueHandling,
                EqualityComparer = serializer.EqualityComparer,
                // No Get access to the error event, so it cannot be copied.
                // Error = += serializer.Error
                FloatFormatHandling = serializer.FloatFormatHandling,
                FloatParseHandling = serializer.FloatParseHandling,
                Formatting = serializer.Formatting,
                MaxDepth = serializer.MaxDepth,
                MetadataPropertyHandling = serializer.MetadataPropertyHandling,
                MissingMemberHandling = serializer.MissingMemberHandling,
                NullValueHandling = serializer.NullValueHandling,
                ObjectCreationHandling = serializer.ObjectCreationHandling,
                ReferenceLoopHandling = serializer.ReferenceLoopHandling,
                // Copying the reference resolver doesn't work in the default case, since the
                // actual BidirectionalDictionary<string, object> mappings are held in the 
                // JsonSerializerInternalBase.
                // See https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs
                ReferenceResolverProvider = () => serializer.ReferenceResolver,
                PreserveReferencesHandling = serializer.PreserveReferencesHandling,
                StringEscapeHandling = serializer.StringEscapeHandling,
                TraceWriter = serializer.TraceWriter,
                TypeNameHandling = serializer.TypeNameHandling,
                // Changes in Json.NET 10.0.1
                //TypeNameAssemblyFormat was obsoleted and replaced with TypeNameAssemblyFormatHandling in Json.NET 10.0.1
                //TypeNameAssemblyFormat = serializer.TypeNameAssemblyFormat,
                TypeNameAssemblyFormatHandling = serializer.TypeNameAssemblyFormatHandling,
                //Binder was obsoleted and replaced with SerializationBinder in Json.NET 10.0.1
                //Binder = serializer.Binder,
                SerializationBinder = serializer.SerializationBinder,
            };
            return settings;
        }
    }
    
    public static class StackExtensions
    {
        public struct PushValue<T> : IDisposable
        {
            readonly Stack<T> stack;
    
            public PushValue(T value, Stack<T> stack)
            {
                this.stack = stack;
                stack.Push(value);
            }
    
            // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
            public void Dispose()
            {
                if (stack != null)
                    stack.Pop();
            }
        }
    
        public static PushValue<T> PushUsing<T>(this Stack<T> stack, T value)
        {
            if (stack == null)
                throw new ArgumentNullException();
            return new PushValue<T>(value, stack);
        }
    }
    

    次に、次のように使用します:

    public class RootObject
    {
        public string Name { get; set; }
        public DateTime DateCreated { get; set; }
    
        [JsonProperty(NamingStrategyType = typeof(DefaultNamingStrategy))]
        [JsonConverter(typeof(AlternateContractResolverConverter), typeof(DefaultContractResolver))]
        public SomeDocument SomeDocument { get; set; }
    }
    
    public class SomeDocument
    {
        public string MyFirstProperty { get; set; }
        public string mysecondPROPERTY { get; set; }
        public AnotherRandomSubdoc another_random_subdoc { get; set; }
    }
    
    public class AnotherRandomSubdoc
    {
        public string evenmoredata { get; set; }
        public DateTime DateCreated { get; set; }
    }
    

    (ここでは、 "SomeDocument"が必要であると想定しています。 質問から完全に明確ではありませんが、プロパティ名は逐語的にシリアル化されます。そのために、 JsonPropertyAttribute.NamingStrategyType> Json.NET9.0.1から。以前のバージョンを使用している場合は、プロパティ名を明示的に設定する必要があります。)

    その場合、結果のJSONは次のようになります。

    {
      "name": "Question 40597532",
      "dateCreated": "2016-11-14T05:00:00Z",
      "SomeDocument": {
        "MyFirstProperty": "my first property",
        "mysecondPROPERTY": "my second property",
        "another_random_subdoc": {
          "evenmoredata": "even more data",
          "DateCreated": "2016-11-14T05:00:00Z"
        }
      }
    }
    

    このソリューションは、オブジェクト参照の保持 ではうまく機能しないことに注意してください。 。それらを連携させる必要がある場合は、Json.NETは深さと属性でシリアル化します

    デモフィドルこちら 。

    ちなみに、この質問



    1. mongodbでドキュメントをカスケード削除する方法は?

    2. サーバーデータベースとしてexpress、mongodbを使用したノードjsでのユーザー管理

    3. Mongooseを使用してMongoDBの多くのレコードを更新するための正しいアプローチは何ですか

    4. MongoDBのオブジェクト値に関連する情報を取得します