2017-04-17 1 views
1

Je travaille avec une version plus complexe du contrat de données suivantes, mais cela devrait être suffisant comme exemple:Comment faire en sorte que Swashbuckle respecte DataType lors de la génération de fichiers swagger?

using System; 
using System.Runtime.Serialization; 
using System.ComponentModel; 
using System.ComponentModel.DataAnnotations; 

[DataContract(Namespace = "https://schemas.company.name/api-name/")] 
public class Subscription 
{ 
    [DataMember(IsRequired = true)] 
    public long SubscriptionID { get; set; } 

    [DataMember(IsRequired = true)] 
    public long ProductID { get; set; } 

    [DataMember(IsRequired = true)] 
    public long AccountID { get; set; } 

    [DataMember(IsRequired = true), DataType(DataType.Date)] 
    public DateTime StartDate { get; set; } 

    [DataMember(IsRequired = true), DataType(DataType.Date)] 
    public DateTime EndDate { get; set; } 
} 

La définition fanfaronnades JSON générée par Swashbuckle pour le contrat de données ci-dessus devient ceci:

... 
    "Subscription": { 
     "required": ["subscriptionID", "productID", "accountID", "startDate", "endDate"], 
     "type": "object", 
     "properties": { 
      "subscriptionID": { 
       "format": "int64", 
       "type": "integer" 
      }, 
      "productID": { 
       "format": "int64", 
       "type": "integer" 
      }, 
      "accountID": { 
       "format": "int64", 
       "type": "integer" 
      }, 
      "startDate": { 
       "format": "date-time", 
       "type": "string" 
      }, 
      "endDate": { 
       "format": "date-time", 
       "type": "string" 
      } 
     } 
    }, 
... 

Cependant, vous remarquerez que le JSON definitions.Subscription.properties.startDate.format est "date-time", mais l'annotation DateTypeAttribute dans le code C# est DataType.Date, pas DataType.DateTime.

Comment faire pour que Swashbuckle respecte System.ComponentModel.DataAnnotations.DataTypeAttribute lors de la génération de fichiers Swagger? Ou plus précisément, faire des propriétés de classe annotées avec [DataType(DataType.Date] générer un fanfaronnade format de "date"? Je souhaite que ce soit le comportement par défaut pour toutes les classes, car j'ai trop de détails de code de propriétés de classe spécifiques et est le point entier d'utiliser Swashbuckle pour générer swagger JSON basé sur d'autres annotations à partir de la même espace de noms (tel que System.ComponentModel.DataAnnotations.StringLengthAttribute).

Ma première tentative a été d'essayer d'utiliser un ISchemaFilter dans mon Startup.cs, tels que:

services.AddSwaggerGen(options => 
    { 
     ... 
     options.SchemaFilter<DataTypeSchemaFilter>(); 
     ... 
    }); 

Lorsque la classe de filtre mis en œuvre Appliquer:

public class DataTypeSchemaFilter : ISchemaFilter 
{ 
    public void Apply(Schema model, SchemaFilterContext context) 
    { 
     ??? 
    } 
} 

Cependant, je ne vois aucune possibilité de rechercher les attributs de propriété de classe à partir du filtre à l'aide des paramètres Schema model et SchemaFilterContext context fournis. Comme mentionné précédemment, je sais que Swashbuckle regarde les attributs à l'intérieur du même espace de noms lors du traitement des propriétés de classe, donc j'espère que quelqu'un sait où je peux lier dans Swashbuckle et effectuer une tâche similaire.

Répondre

1

J'ai écrit le code ci-dessous. Essentiellement, l'idée est que vous joignez les noms de propriété de la classe aux noms de propriété de schéma (schema.properties). Étant donné que vous pouvez avoir des paramètres de sérialiseur personnalisés (cas de chameau), l'enveloppe des noms de propriété peut être différente dans le schéma que celle définie dans la classe. J'ai également inclus le schéma parent dans la méthode SetSchemaDetails afin que vous puissiez ajouter des attributs au niveau parent si nécessaire. Nous avons des attributs obligatoires personnalisés que nous utilisons occasionnellement, nous devons donc spécifier les propriétés requises au niveau du schéma parent (classe englobante) plutôt qu'au niveau du schéma de propriété.

public class DataAnnotationSchemaFilter : ISchemaFilter 
{ 
    public void Apply(Schema schema, SchemaFilterContext schemaFilterContext) 
    { 
     var type = schemaFilterContext.SystemType; 

     var propertyMappings = type 
      .GetProperties() 
      .Join(
       schema.Properties ?? new Dictionary<string, Schema>(), 
       x => x.Name.ToLower(), 
       x => x.Key.ToLower(), 
       (x, y) => new KeyValuePair<PropertyInfo, KeyValuePair<string, Schema>>(x, y)) 
      .ToList(); 

     foreach (var propertyMapping in propertyMappings) 
     { 
      var propertyInfo = propertyMapping.Key; 
      var propertyNameToSchemaKvp = propertyMapping.Value; 

      foreach (var attribute in propertyInfo.GetCustomAttributes()) 
      { 
       SetSchemaDetails(schema, propertyNameToSchemaKvp, propertyInfo, attribute); 
      } 
     } 
    } 

    private static void SetSchemaDetails(Schema parentSchema, KeyValuePair<string, Schema> propertyNameToSchemaKvp, PropertyInfo propertyInfo, object propertyAttribute) 
    { 
     var schema = propertyNameToSchemaKvp.Value; 

     if (propertyAttribute is DataTypeAttribute) 
     { 
      var dataType = ((DataTypeAttribute)propertyAttribute).DataType; 
      if (dataType == DataType.Date) 
      { 
       schema.Format = "date"; 
       schema.Type = "date"; 
      } 
     } 

     if (propertyAttribute is ReadOnlyAttribute) 
     { 
      schema.ReadOnly = ((ReadOnlyAttribute)propertyAttribute).IsReadOnly; 
     } 
    } 
} 
+0

Pouvez-vous indiquer de quel espace de noms provient votre ISchemaFilter? Celui que j'ai trouvé dans 'Swashbuckle.SwaggerGen.Generator.ISchemaFilter' n'a pas le même prototype de fonction. – Sybeus

+0

Swashbuckle.Swagger.ISchemaFilter. J'utilise v5.4.0. – fbhdev

+0

Correction pour AspNetCore. – fbhdev