RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.67k stars 1.23k forks source link

Flattening a class is not respecting the Order specified on the JsonProperty attributes #4734

Open jcachat opened 7 months ago

jcachat commented 7 months ago

I am flattening several of my classes. All properties in all classes have a JsonProperty attribute to specify the Order such that once flattened, they should be ordered in a logical order. But during the flattening, that Order is being completely ignored.

I am currently working around this using an ISchemaProcessor to do that manually. But, it's kind of a mess with all the referenced schemas, reflection, property name mappings, and such.

Can this be fixed?

jcachat commented 7 months ago

If it helps or someone else has the same issue, this is the ISchemaProcessor I created to re-order the properties.

    public class NSwagOrderPropertiesSchemaProcessor : ISchemaProcessor
    {
        public void Process(SchemaProcessorContext context)
        {
            //  Ignore references and properties.
            if (context.Schema.Reference != null)
                return;
            if (context.Schema is JsonSchemaProperty)
                return;

            //  Get the properties of the class so that we can get the JsonPropertyAttributes.
            var properties = context.ContextualType.Type.GetProperties();
            if (!properties.Any(p => p.HasAttribute<JsonPropertyAttribute>()))
                return;     //  Skip if no JsonProperty attributes (i.e. NetTopology Geometry). Also avoids duplicate property name issue with Geometry.

            //  Get the order of the properties from the JsonProperty attribute along with the configured property name in case it is being remapped.
            var orderLookup = properties
                .Select(p => new { prop = p, attr = p.GetCustomAttribute<JsonPropertyAttribute>() })
                .ToDictionary(a => a.attr?.PropertyName ?? a.prop.Name, a => a.attr?.Order ?? 0);

            var sorted = context.Schema.Properties.OrderBy(p => orderLookup[p.Key]).ThenBy(p => p.Key).ToList();

            context.Schema.Properties.Clear();
            foreach (var item in sorted)
                context.Schema.Properties.Add(item.Key, item.Value);
        }
    }