How to serialize or deserialize a JSON Object to a certain depth in C#?

后端 未结 4 1054
鱼传尺愫
鱼传尺愫 2020-12-05 14:03

I only want the first depth level of an object (I do not want any children). I am willing to use any library available. Most libraries will merely throw an exception when

4条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-05 15:03

    First, I wanted to say all credit should go to Nathan Baulch. This is an adaptation of his answer combined with using the MaxDepth in settings. Thanks for your help Nathan!

    using Newtonsoft.Json;
    using Newtonsoft.Json.Serialization;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using System.Web.Mvc;
    
    namespace Helpers
    {
        public class JsonNetResult : JsonResult
        {
            public JsonNetResult()
            {
                Settings = new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Error
                };
            }
    
            public JsonSerializerSettings Settings { get; private set; }
    
            public override void ExecuteResult(ControllerContext context)
            {
                if (context == null)
                    throw new ArgumentNullException("context");
                if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
                    throw new InvalidOperationException("JSON GET is not allowed");
    
                HttpResponseBase response = context.HttpContext.Response;
                response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;
    
                if (this.ContentEncoding != null)
                    response.ContentEncoding = this.ContentEncoding;
                if (this.Data == null)
                    return;
    
                var scriptSerializer = JsonSerializer.Create(this.Settings);
    
                using (var sw = new StringWriter())
                {
                    if (Settings.MaxDepth != null)
                    {
                        using (var jsonWriter = new JsonNetTextWriter(sw))
                        {
                            Func include = () => jsonWriter.CurrentDepth <= Settings.MaxDepth;
                            var resolver = new JsonNetContractResolver(include);
                            this.Settings.ContractResolver = resolver;
                            var serializer = JsonSerializer.Create(this.Settings);
                            serializer.Serialize(jsonWriter, Data);
                        }
                        response.Write(sw.ToString());
                    }
                    else
                    {
                        scriptSerializer.Serialize(sw, this.Data);
                        response.Write(sw.ToString());
                    }
                }
            }
        }
    
        public class JsonNetTextWriter : JsonTextWriter
        {
            public JsonNetTextWriter(TextWriter textWriter) : base(textWriter) { }
    
            public int CurrentDepth { get; private set; }
    
            public override void WriteStartObject()
            {
                CurrentDepth++;
                base.WriteStartObject();
            }
    
            public override void WriteEndObject()
            {
                CurrentDepth--;
                base.WriteEndObject();
            }
        }
    
        public class JsonNetContractResolver : DefaultContractResolver
        {
            private readonly Func _includeProperty;
    
            public JsonNetContractResolver(Func includeProperty)
            {
                _includeProperty = includeProperty;
            }
    
            protected override JsonProperty CreateProperty(
                MemberInfo member, MemberSerialization memberSerialization)
            {
                var property = base.CreateProperty(member, memberSerialization);
                var shouldSerialize = property.ShouldSerialize;
                property.ShouldSerialize = obj => _includeProperty() &&
                                                  (shouldSerialize == null ||
                                                   shouldSerialize(obj));
                return property;
            }
        }
    }
    

    Use:

    // instantiating JsonNetResult to handle circular reference issue.
    var result = new JsonNetResult
    {
        Data = <>,
        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
        Settings =
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                MaxDepth = 1
            }
    };
    
    return result;
    

提交回复
热议问题