Home > Net >  How to generate JsonPropertyName dynamically?
How to generate JsonPropertyName dynamically?

Time:09-07

I have the below Model class,

using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;

public class FormField
{
    [Required]
    [JsonPropertyName("STD_USERTYPEID")]
    public string UserTypeId { get; set; }

    [Required]
    [JsonPropertyName("STD_OFFICETYPEID")]
    public string OfficeTypeId { get; set; }
}

I have a few scenarios where STD_OFFICETYPEID may come as LegacyOFFICETYPEID or OfficeID. Is there a way in which I can dynamically generate JsonPropertyName? I am using System.Text.Json NuGet package.

Note that this example is simplified. In my production code there could be 20-25 concrete properties. And all of these properties could map to 5-10 different JsonPropertyNames each.

CodePudding user response:

I'll tell you how I would do this: source generators.

First I would inject a new attribute, JsonPropertyNames(params string[] alternativeNames), and I'd decorate my class with it instead, giving it the full list of possible field names.

Then I'd have the source generator generate a second class matching properties with my original class, including properties for each of the alternative names provided using JsonPropertyNames. This is the class you'd be reading the Json into, and all your properties would get read in one of the properties.

Then the generator would add all the necessary AutoMapper mapping code to copy from my generated type to the original type, as well as a helper class that reads into the generated type and invokes AutoMapper to return the class for you.

So from the caller side, you'd just need to call one function to get your type, ignoring all the details behind the scenes.

CodePudding user response:

if you are ready to swith to Newtonsoft.Json you can try this code

var json="{\"STD_USERTYPEID\":\"userId\",\"LegacyOFFICETYPEID\":\"officeId\"}";

FormField formField = DeserializeObj<FormField>(json);

public class FormField
{
    [JsonProperty("STD_USERTYPEID")]
    public string UserTypeId { get; set; }
    
    [JsonPropertyNames(new string[] {"STD_OFFICETYPEID", "LegacyOFFICETYPEID" })]
    public string OfficeTypeId { get; set; }
}

public T DeserializeObj<T>(string json) where T:new()
{
    var jsonObj = JObject.FromObject(new T());
    var attrs = GetAttrs<T>();
    var jsonParsed = JObject.Parse(json);
    foreach (var prop in jsonParsed.Properties())
    {
        var propName=prop.Name;
        
        var attr=attrs.Where(a=>a.AttributeNames.Contains(propName)).FirstOrDefault();
        if(attr!=null) jsonObj[attr.PropertyName]=prop.Value;
        else jsonObj[propName]=prop.Value;
    }
    return jsonObj.ToObject<T>();
}
public static List<PropertyAttributes> GetAttrs<T>()  where T: new()
{
    var source= new T();
    var attrs = new List<PropertyAttributes>();
    
    foreach (PropertyInfo prop in source.GetType().GetProperties())
    {
        var attribute = prop.GetCustomAttribute<JsonPropertyNamesAttribute>();

        if (attribute != null)
        {
            attrs.Add(new PropertyAttributes { PropertyName = prop.Name, AttributeNames = attribute.Names });
        }
    }
    if (attrs.Count > 0) return attrs;
    return null;
}

public class PropertyAttributes
{
    public string PropertyName { get; set; }
    public string[] AttributeNames { get; set; }
}

[AttributeUsage(AttributeTargets.All)]
public class JsonPropertyNamesAttribute : Attribute
{
    private string[] names;

    public JsonPropertyNamesAttribute(string[] names)
    {
        this.names = names;
    }
    public virtual string[] Names
    {
        get { return names; }
    }
}
  • Related