Serialize Enum values with JSON structure


Sample Enum and JSON structure
Enum Structure
// our sample Enum
[DataContract(Name = "AppointmentStatus")]
public enum enAppointmentStatus
{
   [EnumMember(Value = "unknown")]
   unknown,
   
   [EnumMember(Value = "booked")]
   booked,
   
   [EnumMember(Value = "needs time")]
   needs_time,
   
   [EnumMember(Value = "pending")]
   pending,
   
   [EnumMember(Value = "cancelled")]
   cancelled,
   
   [EnumMember(Value = "no show")]
   no_show,
   
   [EnumMember(Value = "late")]
   late,
   
   [EnumMember(Value = "drop")]
   drop
}

JSON Structure for serialization
[DataContract]
public class Appointment
{
   [DataMember]
   public string FirstName { get; set; } = string.Empty;

   [DataMember]
   public string LastName { get; set; } = string.Empty;
   
   [DataMember]
   public enAppointmentStatus AppointmentStatus { get; set; };
}

Default Behavior
Serializing the above structure will result in the Enum integer value being generated and not the text.
{
   "First Name": "Bruce",
   "LastName": "Leclaire",
   "AppointmentStatus": 2
}

Outputting the Enum strings using built-in functionality
Update the JSON structure definition. Add the 'JsonConverter' attribute to the AppointmentStatus property.
[DataMember]
[JsonConverter(typeof(StringEnumConverter))]
public enAppointmentStatus AppointmentStatus { get; set; };

This will result in the following being output when serialized.
{
   "First Name": "Bruce",
   "LastName": "Leclaire",
   "AppointmentStatus": "needs time"
}

Customizing the Output Generated
The generated output can be customized. In this case, if the Enum value is 'unknown', it will output 'null' for that member. Update the JSON structure with the following serialized property.
[DataContract]
public class Appointment
{
   [DataMember]
   public string FirstName { get; set; } = string.Empty;

   [DataMember]
   public string LastName { get; set; } = string.Empty;
   
   //[DataMember]   // Remove the attributes for this property
   //[JsonConverter(typeof(StringEnumConverter))]
   public enAppointmentStatus AppointmentStatus { get; set; }
   
   // add a new property that will be used during serialization
   [DataMember(Name = "AppointmentStatus")] 
   public string AppointmentStatus_serialized 
   {
      get
      {
         if (this.AppointmentStatus == enAppointmentStatus.unknown)
         {
            return null;         
         }
         else
         {
            // Get the EnumMember value for the given enum value
            var rv = Utilities.GetEnumMemberAttrValue(this.ActivityTypeEnum);
            return rv;
         }
      }
      set
      {
         if (string.IsNullOrWhiteSpace(value))
         {
            // an empty/blank string was passed in.
            this.AppointmentStatus = enAppointmentStatus.unknown;
         }
         else
         {
            // parse our input value to our Enum
            this.AppointmentStatus = Utilities.ParseEnumWithSpaces(value);
         }            
      }
   }
}
See the following pages for descriptions and definitions of the GetEnumMemberAttrValue and ParseEnumWithSpaces functions.

Allowing for text values that are not part of the Enum
The following is an example of allowing text values that are not part of an Enum to be saved to the JSON structure and included during serialization.

Update the Appointment class to include a private 'override' member.
[DataContract]
public class Appointment
{
   [DataMember]
   public string FirstName { get; set; } = string.Empty;

   [DataMember]
   public string LastName { get; set; } = string.Empty;
   
   [DataMember]
   public enAppointmentStatus AppointmentStatus { get; set; };
   
   // private member to be used in overriding the text for the Appointment Status.   
   private string? _overrideAppointmentStatus { get; set; } = null;	
}

Update the 'AppointmentStatus_serialized' property to handle the custom override text.
public class Appointment
{
   public string? AppointmentStatus_serialized
   {
      // return the text for the Enum value or the override text, if any.
      get
      {
         if (this.AppointmentStatus == enAppointmentStatus.unknown)
         {
            // The Enum value is 'unknown', see if we have an override value
            if (string.IsNullOrWhiteSpace(this._overrideAppointmentStatus))
            {
               // no override value, return null.
               return null;
            }
            else
            {
               // We have an override value, return it.
               return this._overrideAppointmentStatus;
            }
         }
         else
         {
            // Get the EnumMember value for the given enum value
            var rv = Utilities.GetEnumMemberAttrValue(this.AppointmentStatus);
            return rv;
         }
      }
      // Set our enum based on the specified text.
      set
      {
         if (string.IsNullOrWhiteSpace(value))
         {
            // An empty/blank string was passed in
            // clear everything
            this.AppointmentStatus = enAppointmentStatus.Unknown;
            this._overrideAppointmentStatus = null;
         }
         else
         {
            // parse our input value to our Enum
            this.AppointmentStatus = FirstKey.Dyn.Common.Util.Utilities.ParseEnumWithSpaces(value);
     
            if (this.AppointmentStatus == enAppointmentStatus.Unknown)
            {
               // String could not be parsed to an existing enum.
               // Save the value to the activity type enum.
               this._overrideAppointmentStatus = value;
            }
            else
            {
               // We were able to parse input string to an existing enum.
               // Clear the override activity type
               this._overrideAppointmentStatus = null;
            }
         }            
      }
   }
}

An example of using custom text.
Appointment appt = new Appointment();
appt.FirstName = "Bruce";
appt.LastName = "Leclaire";
   
// set our Appointment status to a value that is not part of the Enum listing.
appt.AppointmentStatus_serialized = "Tentative";

Serializing the above will output the following:
{
   "FirstName": "Bruce",
   "LastName": "Leclaire",
   "AppointmentStatus": "Tentative"
}

Last modified by Mohit @ 4/20/2025 1:44:17 PM