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

时间:2016-03-18 11:01:30

标签: c# asp.net-core asp.net-core-mvc asp.net-core-1.0

几周后我一直在研究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[]是类型时,我在正文中有以下值:

{

  ["value","sdjklgsdjlg"]

}

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

{"sdjklgsdjlg"}

也尝试了这个:

{"value":"sdjklgsdjlg"}

我错过了什么吗?我之前读过,旧WebApi用于处理与复杂对象和普通参数的JSON映射的方式,它在.NET Core中以类似的方式工作。

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

context.Request variable problems

context.Request.Body errors

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

6 个答案:

答案 0 :(得分: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" },那么它应该按预期执行。

答案 1 :(得分:4)

这对我有用:

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

答案 2 :(得分:3)

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

答案 3 :(得分:1)

您也可以这样做:

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

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

答案 4 :(得分: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"]

答案 5 :(得分: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"