1

I am using JsonForm to produce dynamic forms in my MVC core web application. I am using System.Text.Json.JsonSerializer.Serialize in the following code in my view model to produce a simple one field form. My aim is to store this json in the database eventually and retrieve it from there.

 public TestsViewModel GetFormControls1()
        {
            var myJsonModel = new
            {
                schema = new
                {
                    client = new
                    {
                        type = "object",
                        title = "Client",
                        properties = new
                        {
                            forename = new
                            {
                                type = "string",
                                title = "Forename",
                                minLength = 3,
                                maxLength = 10,
                            }
                        }
                    }
                },
                form = new List<Object>
                {
                    new {
                        key = "client.forename",
                        title = "Forename"
                    }
                },
                value = new
                {
                    client = new
                    {
                        forename = "",
                    }
                }
            };

            TestsViewModel homeVm = new TestsViewModel();
            homeVm.FormControls = System.Text.Json.JsonSerializer.Serialize(myJsonModel);
            return homeVm;
        }

Above code works fine and produces following json schema which is then used to create a form.

{
  "schema": {
    "client": {
      "type": "object",
      "title": "Client",
      "properties": {
        "forename": {
          "type": "string",
          "title": "Forename",
          "minLength": 3,
          "maxLength": 10
        }
      }
    }
  },
  "form": [
    {
      "key": "client.forename",
      "title": "Forename"
    }
  ],
  "value": {
    "client": {
      "forename": ""
    }
  }
}

I now need to produce an enum for my json so that a drop down for selecting a gender can appear in the form. However, I am unable to do that via c# code. Can someone help? I would like my c# code to produce following json (note two entries for gender in schema and form).

{
  "schema": {
    "client": {
      "type": "object",
      "title": "Client",
      "properties": {
        "forename": {
          "type": "string",
          "title": "Forename",
          "minLength": 3,
          "maxLength": 10
        },
        "gender": {
          "type": "string",
          "title": "Gender",
          "enum": [
            "male",
            "female",
            "alien"
          ]
        }
      }
    }
  },
  "form": [
    {
      "key": "client.forename",
      "title": "Forename"
    },
    {
      "key": "client.gender",
      "titleMap": {
        "male": "Dude",
        "female": "Dudette",
        "alien": "I'm from outer space!"
      }
    }
  ],
  "value": {
    "client": {
      "forename": ""
    }
  }
}

I have tried using following code but enum is a keyword in c# so I get error.

gender = new
                            {
                                type = "string",
                                title = "Gender",
                                enum = "[male, female, alien]"
                            }

Also Enum = "[male, female, alien]" produces "Enum": "[male, female, alien]" instead of "enum": [ "male", "female", "alien" ]

I have a gender lookup table which I will be eventually using to produce above enum somehow so any idea regarding that would be helpful as well.

UPDATE @dbc's comment provides solution to most of my problem. However, I am still struglling with producing titleMap json if I try to map string to an int.

var gender3 = new
            {
                type = "string",
                title = "Gender",
                titleMap = new List<string> { new string("1" + ":" + "Male"), new string("2" + ":" + "Female")}
            };

Above code produces

{
  "type": "string",
  "title": "Gender",
  "titleMap": [
    "1:Male",
    "2:Female"
  ]
}

However, I need both 1 and Male in their own double quotations inside { } instead of [ ] as shown below.

{
  "type": "string",
  "title": "Gender",
  "titleMap": {
    "1": "Male",
    "2": "Female"
  }
}
learner
  • 581
  • 7
  • 27
  • 2
    Your question is quite long, but are you just looking for `@enum = new [] { "male", "female", "alien" },`? See https://dotnetfiddle.net/dwZFsW. See: [How do I use a C# keyword as a property name?](https://stackoverflow.com/q/421257/3744182) and also [All possible array initialization syntaxes](https://stackoverflow.com/q/5678216/3744182) for the array initializer syntax for an array of strings. – dbc Jan 24 '20 at 21:07
  • @dbc This resolves most of my queries. Please see update section above for the remaining issue. Also add your comment into Answer section so that I can accept it. – learner Jan 25 '20 at 12:57

2 Answers2

2

enum is a keyword in C# so you need to prepend @ to enum

gender = new
                            {
                                type = "string",
                                title = "Gender",
                                @enum = new string[3]{"male", "female", "alien"}
                            }
divyang4481
  • 1,584
  • 16
  • 32
1

From what I understand, you are trying to serialize an array of enum values as their text names into JSON. The simplest solution for that is to add an array or list of enums property to your TestViewModel and use the JsonStringEnumConverter converter to serialize them as strings rather than numbers.

Here's an example of how you could achieve what you are looking for.

Let's say you have some enum with a set of values:

//This is an arbitrary enum, this could be 'Gender', in your case
public enum TestEnum
{
    value1,
    value2,
    value3,
    value4,
}

And you want to write down an array of those enum values. Add a list of enums property (or array of enums) to your model. If you want the property name within the JSON to be one of the reserved words (like enum) either override the name using the JsonPropertyName attribute (and keep the name whatever makes most sense programmatically):

public class TestsViewModel_Option1
{
    // In your case, this property could be called 'Genders' to be self-documenting
    [JsonPropertyName("enum")]
    public List<TestEnum> ListOfEnums { get; set; }
}

OR, use the @ symbol if you really want the property name to be the reserved keyword and don't want to/can't use the attribute for some reason.

public class TestsViewModel_Option2
{
    // Or use fixed-size array, TestEnum[], if needed
    public List<TestEnum> @enum { get; set; }
}

And now this is what your code looks like with the JsonSerializer:

private static void SerializeListOfEnums()
{
    var model1 = new TestsViewModel_Option1
    {
        ListOfEnums = { TestEnum.value1, TestEnum.value3 }
    };

    var options = new JsonSerializerOptions
    {
        Converters = { new JsonStringEnumConverter() }
    };

    // {"enum":["value1","value3"]}
    Console.WriteLine(JsonSerializer.Serialize(model1, options));

    var model2 = new TestsViewModel_Option2
    {
        @enum = { TestEnum.value1, TestEnum.value3 }
    };

    // {"enum":["value1","value3"]}
    Console.WriteLine(JsonSerializer.Serialize(model2, options));
}
ahsonkhan
  • 2,285
  • 2
  • 11
  • 15