10 votes

Spécifier le type de contenu pour les fichiers en multipart/form-data pour Swagger

J'ai implémenté un point de terminaison avec cette signature

[HttpPost("Test")]
public IActionResult MyTest([Required] IFormFile pdf, [Required] IFormFile image)
{
    // some stuff...

    return Ok();
}

cela génère l'entrée suivante dans swagger.json (la partie pertinente)

"content": {
    "multipart/form-data": {
        "schema": {
            "required": [
                "image",
                "pdf"
            ],
            "type": "object",
            "properties": {
                "pdf": {
                    "type": "string",
                    "format": "binary"
                },
                "image": {
                    "type": "string",
                    "format": "binary"
                }
            }
        },
        "encoding": {
            "pdf": {
                "style": "form"
            },
            "image": {
                "style": "form"
            }
        }
    }
}

mais, je dois aussi spécifier l'encodage, comme dans les caractéristiques (v3). Donc pour ma tâche, ce JSON devrait ressembler à ceci, je pense...

"encoding": {
    "pdf": {
        "style": "form",
        "contentType": "application/pdf"
    },
    "image": {
        "style": "form",
        "contentType": "image/png, image/jpeg"
    }
}

Mais comment puis-je faire cela à partir du code ? J'ai pensé à Attribut SwaggerParameter mais il ne contient que la description et le drapeau requis...

J'utilise le paquet Swashbuckle.AspNetCore NuGeT (version 5.0.0-rc2) sur .NET Core 2.2.

4voto

zhuber Points 2902

Si vous regardez cette ligne vous verrez que l'encodage est créé avec seulement Style tandis que ContentType n'est pas défini. Ce que vous pouvez faire, c'est de le définir manuellement en créant des paramètres personnalisés. Attribute où vous définissez votre type de contenu :

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter,AllowMultiple = false)]
public class OpenApiEncodingContentTypeAttribute : Attribute
{
    public OpenApiEncodingContentTypeAttribute(string contentType)
    {
        ContentType = contentType;
    }

    public string ContentType { get; }
}

et ensuite utiliser cette Attribute sur IOperationFilter

public class FormContentTypeSchemaOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var contentTypeByParameterName = context.MethodInfo.GetParameters()
            .Where(p => p.IsDefined(typeof(OpenApiEncodingContentTypeAttribute), true))
            .ToDictionary(p => p.Name, s => s.GetCustomAttribute<OpenApiEncodingContentTypeAttribute>().ContentType);

        if (contentTypeByParameterName.Any())
        {
            foreach (var requestContent in operation.RequestBody.Content)
            {
                var encodings = requestContent.Value.Encoding;
                foreach (var encoding in encodings)
                {
                    if (contentTypeByParameterName.TryGetValue(encoding.Key, out string value))
                    {
                        encoding.Value.ContentType = value;
                    }
                }
            }
        }
    }
}

Ensuite, il suffit de décorer vos paramètres avec ceci Attribute

[HttpPost("Test")]
public IActionResult MyTest([Required] [OpenApiEncodingContentType("application/pdf")] IFormFile pdf, [Required] [OpenApiEncodingContentType("image/png, image/jpeg")] IFormFile image)
{
    // some stuff...
    return Ok();
}

N'oubliez pas non plus de définir votre IOperationFilter sur AddSwaggerGen

services.AddSwaggerGen(opts =>
{
    // all other stuff
    opts.OperationFilter<FormContentTypeSchemaOperationFilter>();
})

Voici ce que vous obtenez

"requestBody": {
  "content": {
    "multipart/form-data": {
      "schema": {
        "required": [
          "image",
          "pdf"
        ],
        "type": "object",
        "properties": {
          "pdf": {
            "type": "string",
            "format": "binary"
          },
          "image": {
            "type": "string",
            "format": "binary"
          }
        }
      },
      "encoding": {
        "pdf": {
          "contentType": "application/pdf",
          "style": "form"
        },
        "image": {
          "contentType": "image/png, image/jpeg",
          "style": "form"
        }
      }
    }
  }
}

Vous pouvez probablement améliorer IOperationFilter avec des vérifications supplémentaires, des contrôles de nullité et d'autres éléments adaptés à vos besoins, car il ne s'agit que d'une mise en œuvre de base.

0voto

Martin Points 21

Vous pouvez également jeter un coup d'œil à ISchemaFilter et au problème suivant :

https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1148

Cela peut vous aider à filtrer votre opération et à ajouter les différents contentStyles pour le même type (IFormInput).

Je pense que ce que vous voulez réaliser n'est actuellement possible qu'avec un attribut personnalisé, cependant il y a une branche active pour un support FormsInput amélioré en développement actif, peut-être pouvez-vous ajouter une demande de fonctionnalité.

https://github.com/domaindrivendev/Swashbuckle.AspNetCore/commits/enhance-support-for-forms

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X