ASP.NET Core无法读取请求正文

问题描述 投票:9回答:6

几个星期以来,我一直在研究ASP.NET Core。我试图在这个博客上实现一些目标:Microservices

我的project.json如下:

{
  "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"
  ]
}

ConfigureServices中的Startup.cs方法如下:

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
}

这是我在Startup.cs中的Confiure方法:

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();
}

AuthorizationController如下:

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

Post方法最初有[FromBody]string[] value。我通过使它成为一个简单的string类型进一步简化了它。我在Chrome上使用Advance Rest Client发送HTTP request。当string[]是类型I时,身体中有以下值:

{

  ["value","sdjklgsdjlg"]

}

简化参数后,我尝试使用以下正文发送请求:

{"sdjklgsdjlg"}

尝试过这个:

{"value":"sdjklgsdjlg"}

我错过了什么吗?我之前读过,旧的Web Api过去与JSON映射到复杂对象和普通参数的工作方式有关,它在.NET Core中以类似的方式工作。

此外,我应该详细说明断点在所有中间件和控制器上正常命中。但是没有一个中间件似乎能够读取Request的流相关内容:

context.Request variable problems

context.Request.Body errors

请告诉我我在哪里遇到问题。非常感谢!

c# asp.net-core asp.net-core-mvc asp.net-core-1.0
6个回答
4
投票

[FromBody]使用已注册的格式化程序将提交数据的整个主体解码为应用它的单个参数 - 默认情况下,唯一注册的格式化程序接受JSON。

在JSON中,没有直接表示字符串的有效方法 - {"sdjklgsdjlg"}不是有效的JSON,{"value":"sdjklgsdjlg"}是,但不会反序列化为简单的字符串参数。编辑:请参阅@tmg的答案,这可以使用语法{ "": "sdjklgsdjlg" }完成

因此,您需要某种特定的模型类来表示您试图从身体获得的输入,例如:

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

那么你应该能够成功地做到:

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

现在,如果你发布{ "Value": "some value" },它应该做你期望的。


4
投票

这对我有用:

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

3
投票

马克休斯的回答是正确的,直到某一点。如果你发布这种格式的json,{ "": "sdjklgsdjlg" }模型绑定器应该能够将它绑定到简单的字符串模型,而不需要包装器模型。


1
投票

你也可以这样做:

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

或者用户[FromQuery]并直接传递Querystring值。


1
投票

我在这里很晚,但想分享确切的原因,以便任何其他用户都能获得准确的信息。

您无法在控制器上获取值,因为您将数据作为JSON对象发布:

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

为了解决这个问题,我们需要另一个对象来绑定这些数据。控制器的动作是这样的:

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

这里CustomViewModel是一个类:

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

如果您想根据当前的操作签名获取数据:

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

然后,您需要在请求正文中将数据作为JSON字符串传递:

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

类似于字符串数组操作:

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

在请求体中传递字符串的JSON数组:

["item1", "item2"]

0
投票

您应该使用所有依赖项的RC2版本。 有https://github.com/aspnet/KestrelHttpServer/issues/915我发现默认情况下System.Threading.Tasks.Extensions的版本是4.0.0。所以你应该在project.json文件中明确指定这个包的版本:

"System.Threading.Tasks.Extensions": "4.0.0-rc2-24027"
© www.soinside.com 2019 - 2024. All rights reserved.