Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8563479
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 11, 20262026-06-11T16:58:10+00:00 2026-06-11T16:58:10+00:00

Fundamentally, I want to include or omit a property from the generated Json based

  • 0

Fundamentally, I want to include or omit a property from the generated Json based on its value at the time of serialization.

More-specifically, I have a type that knows if a value has been assigned to it and I only want to serialize properties of that type if there has been something assigned to it (so I need to inspect the value at runtime). I’m trying to make it easy for my API to detect the difference between “has the default value” and “wasn’t specified at all”.

A custom JsonConverter does not seem sufficient; I tried it and I believe the property name is already serialized before the converter is called. In my case I want to omit even the property name.

I’ve looked at extending DefaultContractResolver but CreateProperty and CreateProperties (which return JsonProperty serialization metadata) take only the Type being serialized, so I can’t inspect the instance itself. In general, I don’t see anything on the DefaultContractResolver allowing me to control if an instance is serialized; maybe I missed it.

I also thought maybe I needed to create a ContractResolver that returned a custom JsonObjectContract for my type. But, again, I don’t see anything on JsonObjectContract that makes decisions based on an instance.

Is there a good way to accomplish my goal? Am I just missing something simple? Any help you can provide is greatly appreciated. Since Json.NET is so extensible, I thought this wouldn’t be too hard. But I’m starting to think I’m way off in the weeds here. 🙂

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-11T16:58:11+00:00Added an answer on June 11, 2026 at 4:58 pm

    Ok, after digging around in Json.NET source for a while, I finally got this working and it will even honor the ShouldSerialize* and *Specified members that Json.NET supports. Be warned: this is definitely going off into the weeds.

    So I realized that the JsonProperty class returned by DefaultContractResolver.CreateProperty has ShouldSerialize and Converter properties, which allow me to specify if the property instance should actually be serialized and, if so, how to do it.

    Deserialization requires something a little different, though. DefaultContractResolver.ResolveContract will, by default for a custom type, return a JsonObjectContract with a null Converter property. In order to deserialize my type properly, I needed to set the Converter property when the contract is for my type.

    Here’s the code (with error handling / etc removed to keep things as small as possible).

    First, the type that needs special handling:

    public struct Optional<T>
    {
        public readonly bool ValueProvided;
        public readonly T Value;
    
        private Optional( T value )
        {
            this.ValueProvided = true;
            this.Value = value;
        }
    
        public static implicit operator Optional<T>( T value )
        {
            return new Optional<T>( value );
        }
    }
    

    And there’s the converter that will serialize it properly after we know it should be serialized:

    public class OptionalJsonConverter<T> : JsonConverter
    {
        public static OptionalJsonConverter<T> Instance = new OptionalJsonConverter<T>();
    
        public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
        {
            var optional = (Optional<T>)value; // Cast so we can access the Optional<T> members
            serializer.Serialize( writer, optional.Value );
        }
    
        public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
        {
            var valueType = objectType.GetGenericArguments()[ 0 ];
            var innerValue = (T)serializer.Deserialize( reader, valueType );
            return (Optional<T>)innerValue; // Explicitly invoke the conversion from T to Optional<T>
        }
    
        public override bool CanConvert( Type objectType )
        {
            return objectType == typeof( Optional<T> );
        }
    }
    

    Finally, and most-verbosely, here’s the ContractResolver that inserts the hooks:

    public class CustomContractResolver : DefaultContractResolver
    {
        // For deserialization. Detect when the type is being deserialized and set the converter for it.
        public override JsonContract ResolveContract( Type type )
        {
            var contract = base.ResolveContract( type );
            if( contract.Converter == null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof( Optional<> ) )
            {
                // This may look fancy but it's just calling GetOptionalJsonConverter<T> with the correct T
                var optionalValueType = type.GetGenericArguments()[ 0 ];
                var genericMethod = this.GetAndMakeGenericMethod( "GetOptionalJsonConverter", optionalValueType );
                var converter = (JsonConverter)genericMethod.Invoke( null, null );
                // Set the converter for the type
                contract.Converter = converter;
            }
            return contract;
        }
    
        public static OptionalJsonConverter<T> GetOptionalJsonConverter<T>()
        {
            return OptionalJsonConverter<T>.Instance;
        }
    
        // For serialization. Detect when we're creating a JsonProperty for an Optional<T> member and modify it accordingly.
        protected override JsonProperty CreateProperty( MemberInfo member, MemberSerialization memberSerialization )
        {
            var jsonProperty = base.CreateProperty( member, memberSerialization );
            var type = jsonProperty.PropertyType;
            if( type.IsGenericType && type.GetGenericTypeDefinition() == typeof( Optional<> ) )
            {
                // This may look fancy but it's just calling SetJsonPropertyValuesForOptionalMember<T> with the correct T
                var optionalValueType = type.GetGenericArguments()[ 0 ];
                var genericMethod = this.GetAndMakeGenericMethod( "SetJsonPropertyValuesForOptionalMember", optionalValueType );
                genericMethod.Invoke( null, new object[]{ member.Name, jsonProperty } );
            }
            return jsonProperty;
        }
    
        public static void SetJsonPropertyValuesForOptionalMember<T>( string memberName, JsonProperty jsonProperty )
        {
            if( jsonProperty.ShouldSerialize == null ) // Honor ShouldSerialize*
            {
                jsonProperty.ShouldSerialize =
                    ( declaringObject ) =>
                    {
                        if( jsonProperty.GetIsSpecified != null && jsonProperty.GetIsSpecified( declaringObject ) ) // Honor *Specified
                        {
                            return true;
                        }                    
                        object optionalValue;
                        if( !TryGetPropertyValue( declaringObject, memberName, out optionalValue ) &&
                            !TryGetFieldValue( declaringObject, memberName, out optionalValue ) )
                        {
                            throw new InvalidOperationException( "Better error message here" );
                        }
                        return ( (Optional<T>)optionalValue ).ValueProvided;
                    };
            }
            if( jsonProperty.Converter == null )
            {
                jsonProperty.Converter = CustomContractResolver.GetOptionalJsonConverter<T>();
            }
        }
    
        // Utility methods used in this class
        private MethodInfo GetAndMakeGenericMethod( string methodName, params Type[] typeArguments )
        {
            var method = this.GetType().GetMethod( methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static );
            return method.MakeGenericMethod( typeArguments );
        }
    
        private static bool TryGetPropertyValue( object declaringObject, string propertyName, out object value )
        {
            var propertyInfo = declaringObject.GetType().GetProperty( propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance );
            if( propertyInfo == null )
            {
                value = null;
                return false;
            }
            value = propertyInfo.GetValue( declaringObject, BindingFlags.GetProperty, null, null, null );
            return true;
        }
    
        private static bool TryGetFieldValue( object declaringObject, string fieldName, out object value )
        {
            var fieldInfo = declaringObject.GetType().GetField( fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance );
            if( fieldInfo == null )
            {
                value = null;
                return false;
            }
            value = fieldInfo.GetValue( declaringObject );
            return true;
        }
    }
    

    I hope that helps somebody else. Feel free to ask questions if anything is unclear or if it looks like I missed something.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Fundamentally, what I want to do is within, for example, ViewControllerA display ViewControllerB and
I want to do following things from main thread/process: Communicate to another process using
My question is very fundamental, I want to know straight forward and right way
I'm sorry if my question title seems fundamentally uninformed. Let me explain what I
I believe my understanding of boost::mpl::set must be fundamentally flawed. I thought it only
I'm trying to wrap my head around Arquillian and am just not fundamentally understanding
I'm writing my thesis/dissertation and since its an on-going work I don't always have
The question I have might be more to do with semantics than with the
Im using google chrome and i want that profile text with the background to
I must be doing something fundamentally wrong. I am implmenting my repositories and then

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.