Question38038793 Collection Item Filtering

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Reflection;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System.Web.SessionState;


    sealed class JsonSkipObjectException : JsonException
    {
    }

    public class ShouldSerializeContractResolver : DefaultContractResolver
    {
        readonly Predicate<object> shouldSerialize;
        readonly SerializationCallback serializationCallback;
        readonly SerializationErrorCallback onErrorCallback;

        public ShouldSerializeContractResolver(Predicate<object> shouldSerialize)
            : base()
        {
            this.shouldSerialize = shouldSerialize;
            this.serializationCallback = (o, context) =>
                {
                    if (shouldSerialize != null && !this.shouldSerialize(o))
                        throw new JsonSkipObjectException();
                };
            this.onErrorCallback = (o, context, errorContext) =>
                {
                    if (errorContext.Error is JsonSkipObjectException)
                    {
                        errorContext.Handled = true;
                    }
                };
        }

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);

            if (shouldSerialize != null)
            {
                if (property.Readable)
                {
                    var oldShouldSerialize = property.ShouldSerialize;
                    property.ShouldSerialize = (o) =>
                        {
                            if (oldShouldSerialize != null && !oldShouldSerialize(o))
                                return false;
                            var value = property.ValueProvider.GetValue(o);
                            if (!this.shouldSerialize(value))
                                return false;
                            return true;
					};
                }
            }
            return property;
        }

        protected override JsonContract CreateContract(Type objectType)
        {
            var contract = base.CreateContract(objectType);
            contract.OnSerializingCallbacks.Add(serializationCallback);
            contract.OnErrorCallbacks.Add(onErrorCallback);
            return contract;
        }
    }

    public interface IConditionalSerialization
    {
        bool ShouldSerialize();
    }

    public class ConditionalSerializationObject : IConditionalSerialization
    {
        public bool IsSecret { get; set; }

        public string SecretProperty { get { return "should not see me"; } }

        // Ensure "normal" conditional property serialization is not broken
        public bool ShouldSerializeSecretProperty()
        {
            return false;
        }

        #region IConditionalSerialization Members

        bool IConditionalSerialization.ShouldSerialize()
        {
            return !IsSecret;
        }

        #endregion
    }

    public class TestClass
    {
        public static void Test()
        {
			Test(PreserveReferencesHandling.None);
			Test(PreserveReferencesHandling.Arrays);
			Test(PreserveReferencesHandling.All);
        }
		
        public static void Test(PreserveReferencesHandling preserveReferencesHandling)
        {
            Predicate<object> filter = (o) => 
                {
                    var conditional = o as IConditionalSerialization;
                    return conditional == null || conditional.ShouldSerialize();
                };
            var settings = new JsonSerializerSettings
            {
                ContractResolver = new ShouldSerializeContractResolver(filter),
                PreserveReferencesHandling = preserveReferencesHandling,
            };

            var ok = new ConditionalSerializationObject { IsSecret = false };
            var notOk = new ConditionalSerializationObject { IsSecret = true };

            Test(ok, settings);
            Test(new { Public = ok, Private = notOk }, settings);
            Test(new [] { ok, notOk, ok, notOk }, settings);
            Test(new[,] {{ ok, notOk, ok, notOk }}, settings);
            Test(new { Array = new[,] { { ok, notOk, ok, notOk } } }, settings);
            try
            {
                Test(notOk, settings);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception thrown and not caught as expected when serializing root object " + notOk.GetType() + ":");
                Console.WriteLine(ex);
            }
        }

        static void Test<T>(T value, JsonSerializerSettings settings)
        {
            Console.WriteLine("Unfiltered object: ");
            Console.WriteLine(JToken.FromObject(value));

            var serializer = JsonSerializer.CreateDefault(settings);
            var token = JToken.FromObject(value, serializer);
            Console.WriteLine("Filtered object: ");
            Console.WriteLine(token);
            if (!token.SelectTokens("..IsSecret").All(t => JToken.DeepEquals(t, (JValue)false)))
            {
                throw new InvalidOperationException("token.SelectTokens(\"..IsSecret\").All(t => JToken.DeepEquals(t, (JValue)true))");
            }
            if (token.SelectTokens("..SecretProperty").Any())
            {
                throw new InvalidOperationException("token.SelectTokens(\"..SecretProperty\").Any()");
            }
            Console.WriteLine("Secret objects and properties were successfully filtered.");
            Console.WriteLine("");
        }
    }

	public class Program
	{
		public static void Main()
		{
			TestClass.Test();
		}
	}
;