问题
Is it possible to generate a schema with Json.NET that outputs enum values as strings rather than integers? I noticed someone had forked the code to do this, but was wondering if there's any other way to do this, or if there are any plans to do it.
EDIT
To be clear, I'm trying to use this to generate a schema:
var schemaGenerator = new JsonSchemaGenerator();
var schema = schemaGenerator.Generate(typeof(Class1));
return schema.ToString();
回答1:
Install Newtonsoft.Json.Schema
package via NuGet package manager, then you can output enums as strings out-of-the-box.
Given classes
public class Foo
{
public Options Bar { get; set; }
}
public enum Options
{
Option1,
Option2
}
Schema would be generated as follows, no need to decorate classes/properties with [JsonConverter(typeof(StringEnumConverter))]
attribute.
JSchemaGenerator generator = new JSchemaGenerator();
generator.GenerationProviders.Add(new StringEnumGenerationProvider());
JSchema schema = generator.Generate(typeof(Foo), false);
//Console.WriteLine(schema);
回答2:
I had the same problem. I wrote a hack which replaces integers with enums via reflection. Still waiting for official fix.
var jsonSchemaString = JsonUtility.getRawJSONSchema(typeof(Class1).FullName);
Not tested with all test cases.
public class JsonUtility
{
public static string getRawJSONSchema(string jsonObjectTypeName)
{
var jsonSchemaGenerator = new JsonSchemaGenerator();
var myType = Type.GetType(jsonObjectTypeName);
var schema = jsonSchemaGenerator.Generate(myType);
schema.Title = myType.Name;
var enumToFix = new Dictionary<string, string>();
FindEnums(schema, myType, ref enumToFix);
var writer = new StringWriter();
var jsonTextWriter = new JsonTextWriter(writer);
schema.WriteTo(jsonTextWriter);
var result = writer.ToString();
ReplaceEnums(ref result, enumToFix);
return result;
}
//This is a known issue with JsonSchemaGenarator
//Stay tuned with future releases of JSON.Net package
//Enums are generator as integers
//Lets convert intergers to string here
private static void FindEnums(JsonSchema schema, Type Type, ref Dictionary<string, string> result)
{
if (schema.Properties != null)
foreach (var prop in schema.Properties)
{
if (prop.Value.Enum != null)
{
var properties = Type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var p in properties)
{
SearchProperty(p, prop.Key, ref result);
}
}
FindEnums(prop.Value, Type, ref result);
}
}
private static void SearchProperty(PropertyInfo property, string propertyName, ref Dictionary<string, string> result)
{
//IF property name is same as JSON property name
if (property.Name.Trim().ToLower() == propertyName.Trim().ToLower())
{
result.Add(property.Name, EnumToJsonArray(property.PropertyType));
return;
}
//Custom JSON property names set via attributes
foreach (CustomAttributeData customAttr in property.CustomAttributes)
{
if (customAttr.AttributeType.Name == "JsonPropertyAttribute")
{
foreach (CustomAttributeNamedArgument arg in customAttr.NamedArguments)
{
if (arg.TypedValue.Value.ToString().Trim().ToLower() == propertyName.Trim().ToLower())
{
result.Add(propertyName, EnumToJsonArray(property.PropertyType));
return;
}
}
foreach (CustomAttributeTypedArgument arg in customAttr.ConstructorArguments)
{
if (arg.Value.ToString().Trim().ToLower() == propertyName.Trim().ToLower())
{
result.Add(propertyName, EnumToJsonArray(property.PropertyType));
return;
}
}
}
}
PropertyInfo[] info = property.PropertyType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
if (info.Length > 0)
{
foreach (var item in info)
{
SearchProperty(item, propertyName, ref result);
}
}
}
private static string EnumToJsonArray(Type type)
{
if (!type.IsEnum)
throw new InvalidOperationException("enum expected");
var results =
Enum.GetValues(type).Cast<object>().Select(enumValue => enumValue.ToString())
.ToList();
return Newtonsoft.Json.JsonConvert.SerializeObject(results);
}
private static void ReplaceEnums(ref string result, Dictionary<string, string> enumToFix)
{
foreach (var item in enumToFix)
{
result = Regex.Replace(result, @"""" + item.Key + ".*?}", @"""" + item.Key + @""":{""required"":true,""type"":""string"",""enum"":" + item.Value + @"}");
}
}
}
回答3:
Use the following code to serialize schema with enums as strings and make sure that value type is also adjusted.
JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
Converters = new List<JsonConverter>()
{
new StringEnumConverter()
}
};
var gen = new JSchemaGenerator()
{
DefaultRequired = Required.Default,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var myType = typeof(ConfigRoot);
var schema = gen.Generate(myType);
var schemaObj = JObject.Parse(schema.ToString());
var enumNodes = schemaObj.SelectTokens("$..enum");
foreach (var node in enumNodes)
{
var enumTypeNode = node.Parent.Parent;
enumTypeNode["type"] = "string";
}
Console.WriteLine(schemaObj.ToString());
来源:https://stackoverflow.com/questions/25719779/generate-schema-using-stringenumconverter