web-dev-qa-db-fra.com

ASP.NET Core ne peut pas lire le corps de la requête

Je travaille sur ASP.NET Core depuis quelques semaines. J'essayais de réaliser quelque chose basé sur ce blog: Microservices

Mon project.json est le suivant:

{
  "version": "1.0.0-*",
  "compilationOptions": {
    "emitEntryPoint": true
  },

  "dependencies": {

    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.Diagnostics": "1.0.0-rc1-*",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
    "EntityFramework.Core": "7.0.0-rc1-final",
    "EntityFramework.Commands": "7.0.0-rc1-final",
    "EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
    "EntityFramework.MicrosoftSqlServer.Design": "7.0.0-rc1-final",
    "Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-rc1-final",
    "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final",
    "System.Security.Cryptography.Algorithms": "4.0.0-beta-23516"

  },

  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel",
    "ef": "EntityFramework.Commands"
  },

  "frameworks": {

    "dnxcore50": {
      "dependencies": {


      }

    }
  },

  "exclude": [
    "wwwroot",
    "node_modules"
  ],
  "publishExclude": [
    "**.user",
    "**.vspscc"
  ]
}

Et la méthode ConfigureServices dans Startup.cs est la suivante:

public void ConfigureServices(IServiceCollection services)
{
    //Registering Authorization Database
    AutorizationAccessRegisteration.RegisterComponents(services, Configuration);

    services.AddMvcCore()
        .AddJsonFormatters(a => a.ContractResolver = new CamelCasePropertyNamesContractResolver());

    //Add cors built in support.
    services.AddCors();

    services.AddMvcCore().AddApiExplorer();

    //Add MVC for supporting WebApi requests
    #region MVC Add

    services.AddMvc();

    services.AddMvc().AddMvcOptions(options =>
    {
        options.RespectBrowserAcceptHeader = true;

        // Input Formatters.
        options.InputFormatters.Clear();

        var jsonInputFormatter = new JsonInputFormatter()
        {
            SerializerSettings = new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
                ,
                DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
                NullValueHandling = NullValueHandling.Ignore
            }
        };


        options.InputFormatters.Add(jsonInputFormatter);

        //Output formater
        //as part of get/post request, set the header Accept = application/json or application/xml
        var jsonOutputFormatter = new JsonOutputFormatter();
        jsonOutputFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        jsonOutputFormatter.SerializerSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore;
        options.OutputFormatters.Insert(0, jsonOutputFormatter);

        options.OutputFormatters.Insert(1, new XmlDataContractSerializerOutputFormatter());

    });

    #endregion
}

Et voici ma méthode Confiure dans Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {

    }
    else if (env.IsStaging())
    {

    }
    else if (env.IsProduction())
    {

    }

    app.UseIISPlatformHandler();

    app.UseCors(builder =>
            builder.WithOrigins("*").AllowAnyHeader().AllowAnyMethod());

    //Middlewares addition to the pipelines:
    /// We add the middlewares in the following fashion:
    /// - Exception Handler
    /// - Logger
    /// - Authorization Handler
    /// There is a big reason of doing that.
    ///
    app.UseExceptionHandler();
    app.UseLoggerHandler();
    app.UseAuthorizationHandler();

    app.UseMvc();
}

Un AuthorizationController est comme suit:

[Route("api/Authorization")]
public class AuthorizationController : Controller
{
 .
     [HttpPost]
     public void Post([FromBody]string value)
     {
     }
 .
}

La méthode Post avait à l'origine [FromBody]string[] value. Je l'ai simplifié davantage en le transformant en un simple type string. J'utilise Advance Rest Client sur Chrome pour envoyer un HTTP request. Quand string[] était le type, les valeurs suivantes étaient dans le corps:

{

  ["value","sdjklgsdjlg"]

}

Après avoir simplifié le paramètre, j'ai essayé d'envoyer une requête avec le corps suivant:

{"sdjklgsdjlg"}

essayé ceci aussi:

{"value":"sdjklgsdjlg"}

Est-ce que je manque quelque chose? J'ai déjà lu la manière dont l'ancien WebApi fonctionnait par rapport au mappage JSON avec les objets complexes et les paramètres normaux. Cela fonctionne de la même manière dans .NET Core.

De plus, je devrais préciser que breakpoint est touché normalement par tous les middlewares et les contrôleurs. Mais aucun middleware ne semble être capable de lire les choses liées au flux de Request:

 context.Request variable problems

 context.Request.Body errors

Veuillez me dire où je fais problème. Merci beaucoup!

9
FreshDev

[FromBody] utilise les formateurs enregistrés pour décoder le corps entier des données soumises en un seul paramètre auquel il est appliqué - par défaut, le seul formateur enregistré accepte JSON.

En JSON, il n'existe aucun moyen valide de représenter directement une chaîne - {"sdjklgsdjlg"} n'est pas un JSON valide, {"value":"sdjklgsdjlg"} l'est, mais ne désérialise pas en un simple paramètre de chaîne. EDIT: Voir la réponse de @tmg, vous pouvez utiliser la syntaxe { "": "sdjklgsdjlg" }

Par conséquent, vous aurez besoin d'une sorte de classe de modèle spécifique pour représenter l'entrée que vous essayez d'obtenir du corps, par exemple:

public class AuthRequest {
    public string Value { get; set; }
}

Ensuite, vous devriez être capable de faire avec succès:

[Route("api/Authorization")]
public class AuthorizationController : Controller
{
    [HttpPost]
    public void Post([FromBody]AuthRequest authReq)
    {
        // authReq.Value should have your value in
    }
}

Maintenant, si vous postez { "Value": "some value" } à cela, il devrait faire ce que vous attendez.

4
Mark Hughes

Mark Hughes répond que c'est correct jusqu'à un moment donné. Si vous postez un json de ce format, le classeur de modèle { "": "sdjklgsdjlg" } devrait pouvoir le lier à un modèle de chaîne simple, sans avoir besoin du modèle d'encapsulation.

3
tmg

Cela fonctionne pour moi:

[HttpPost]
public async Task<IActionResult> CreateApp([FromQuery]string userId)
{
    string appDefinition = await new StreamReader(Request.Body).ReadToEndAsync();
    var newAppJson = JObject.Parse(appDefinition);
...
3
bc3tech

Vous pouvez aussi faire quelque chose comme ça:

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

ou utilisateur [FromQuery] et passez directement une valeur Querystring.

1
Luca Ghersi

Je suis en retard ici, mais je veux partager la raison exacte pour que tout autre utilisateur puisse obtenir des informations précises.

Vous ne pouvez pas obtenir de valeurs sur le contrôleur car vous enregistrez des données en tant qu'objet JSON:

{"value":"sdjklgsdjlg"} //See the curly braces represent an object.

Pour résoudre cela, nous avons besoin d'un autre objet auquel lier ces données. Quelque chose comme ça à l'action du contrôleur:

[HttpPost]
public void Post([FromBody]CustomViewModel data)
{
     ...
    //here you can get value as: data.Value
}

ici CustomViewModel est une classe:

public CustomViewModel
{
    public string Value { get; set; }
}

Si vous souhaitez obtenir des données correspondant à votre signature d'action actuelle:

[HttpPost]
public void Post([FromBody]string value)
{
     ...
}

Ensuite, vous devez transmettre les données sous forme de chaîne JSON dans le corps de la demande:

"sdjklgsdjlg" //notice without any curly braces and property name

De même pour l'action tableau de chaînes:

[HttpPost]
public void Post([FromBody]IEnumerable<string> values)
{
     ...
}

passer un tableau JSON de chaîne dans le corps de la demande:

["item1", "item2"]
1
Prateek Pandey

Vous devriez utiliser la version RC2 de toutes vos dépendances.
Il existe https://github.com/aspnet/KestrelHttpServer/issues/915 J'ai trouvé que la version de System.Threading.Tasks.Extensions est 4.0.0 par défaut. Donc, vous devriez explicitement spécifier la version de ce paquet dans le fichier project.json:

"System.Threading.Tasks.Extensions": "4.0.0-rc2-24027"