web-dev-qa-db-fra.com

ASP.NET Core MVC: Comment obtenir du JSON brut lié à une chaîne sans type?

Semblable à this ancienne question sur les versions antérieures d'ASP.NET, je souhaite que le corps de la requête d'un HTTP POST soit lié à une chaîne. Il semble que le méthode est liée, mais value est nul, lorsque ASP.NET appelle ma méthode de contrôleur:

namespace Demo.Controllers
{

    [Route("[controller]")]
    public class WebApiDemoController : Controller
    {
    ...

    // POST api/values
    [HttpPost]
    public System.Net.Http.HttpResponseMessage Post([FromBody]string value)
    {
       // expected: value = json string, actual: json = null.
    }

Dois-je toujours aller prendre le corps dans un ruisseau? Ou est-ce que ça devrait marcher? Lors du test de la méthode ci-dessus, j'ai utilisé les en-têtes http suivants:

Accept: Application/json
Content-Type: Application/json;charset=UTF-8

Je passe dans le corps ce qui suit: { "a": 1 }

Je ne veux PAS me lier à une variable de chaîne nommée a. Je souhaite lier n'importe quel JSON que je reçois, puis utiliser le contenu JSON, tout contenu arbitraire, à partir de ma méthode.

Si j'ai compris la documentation, le [FromBody]attribut aurait dû faire ce que je voulais, mais je suppose que le mécanisme de liaison MVC ASP.NET ne liera pas un json à une "valeur de chaîne", mais je pourrais peut-être faire autre chose qui me donne un niveau équivalent de flexibilité.

Une question similaire ici me donne l’idée que j’aurais peut-être dû écrire [FromBody] dynamic data à la place d'utiliser [FromBody] string value.

Mise à jour: Ce genre d’astuce doit être envisagée avant de le faire, car si vous souhaitez que le framework .net central gère le codage JSON et XML pour vous, vous venez de détruire cette fonctionnalité. Certains types de serveurs REST peuvent et ont souvent l'obligation de prendre en charge les types de contenu XML et JSON, du moins ceux que j'ai rencontrés et contenant des documents standard.

43
Warren P

Ce qui suit fonctionne dans .net core 1.x, mais pas dans .net core 2.x.

Comme je l'ai dit, la solution consiste à utiliser [FromBody]dynamic data comme liste de paramètres, en utilisant dynamic au lieu de string, et je recevrai un JObject.

Attention: Si votre architecture appelle un seul serveur WebApi pour la production de XML et de JSON, en fonction des entrées d'en-tête de type de contenu, ce type de stratégie de consommation directe JSON peut se retourner contre vous. (Prendre en charge à la fois XML et JSON sur le même service est possible avec suffisamment de travail, mais vous prenez ensuite des éléments qui étaient plus avancés dans le pipeline d’actifs MVC et les intégrez dans vos méthodes de contrôleur, ce qui s’avère contraire à l’esprit de MVC. , où les modèles viennent à vous en tant que POCO déjà analysés)

Une fois que vous convertissez une chaîne dans la méthode, convertissez le JObject entrant (Newtonsoft.JSON dans le type de données en mémoire pour JSON) en une chaîne.

Trouvé à autre réponse ici .

Exemple de code, grâce à Jeson Martajaya:

Avec dynamique:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]dynamic value)
{
   //...
}

Exemple de code avec JObject:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]Newtonsoft.Json.Linq.JObject value)
{
   //...
}
35
Warren P

L'option la plus propre que j'ai trouvée consiste à ajouter votre propre InputFormatter simple:

public class RawJsonBodyInputFormatter : InputFormatter
{
    public RawJsonBodyInputFormatter()
    {
        this.SupportedMediaTypes.Add("application/json");
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var request = context.HttpContext.Request;
        using (var reader = new StreamReader(request.Body))
        {
            var content = await reader.ReadToEndAsync();
            return await InputFormatterResult.SuccessAsync(content);
        }
    }

    protected override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }
}

Et dans votre fichier Startup.cs dans ConfigureServices:

services
    .AddMvc(options =>
    {
        options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
    });

Cela vous permettra d’obtenir la charge utile brute JSON dans vos contrôleurs:

[HttpPost]
public IActionResult Post([FromBody]string value)
{
    // value will be the request json payload
}
27
Saeb Amini

Alternativement, vous pouvez aussi simplement accepter un JObject et vous pourrez utiliser Linq to Json ou même directement ToString() si vous avez vraiment besoin de la chaîne.

5
Fabio Salvalai

Les deux méthodes suivantes fonctionnent dans ASP.NET Core 2 pour lire la chaîne JSON brute.

1) Celui-ci a une meilleure performance.

    [HttpPost]
    public async Task<ActionResult<int>> Process()
    {
        string jsonString;
        using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
        {
            jsonString = await reader.ReadToEndAsync();
        }

2)

    [HttpPost]
    public async Task<ActionResult<int>> Process([FromBody]JToken jsonbody)
    {
        var jsonString = jsonBody.ToString();
2
Xavier John

Je vois que Sam a déjà été voté pour avoir dit à peu près la même chose, mais en testant avec Postman, je constate que si je mets le corps de la requête sur une simple chaîne entre guillemets ASP le lie bien avec l'argument par défaut '[FromBody] string value'.

"just send your string like this without any curly braces"

Pas sûr que application/json soit supposé accepter les données dans ce format. Espérons que, en publiant ce message, une personne bien informée indiquera si cela est valable ou non.

0
Neutrino