web-dev-qa-db-ja.com

ASP.NET Coreがリクエストの本文を読み取れない

私は数週間から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"
  ]
}

また、Startup.csConfigureServicesメソッドは次のとおりです。

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でHTTP requestを送信するためにAdvance Rest Clientを使用しています。string[]がタイプである場合、私は本文で次の値を使用していました:

{

  ["value","sdjklgsdjlg"]

}

パラメータを簡略化した後、次のボディでリクエストを送信してみました:

{"sdjklgsdjlg"}

これも試しました:

{"value":"sdjklgsdjlg"}

何か不足していますか?以前読んだ、古いWebApiがJSONの複雑なオブジェクトと通常のパラメーターへのマッピングに関連して機能していた方法は、.NET Coreでも同様に機能します。

また、breakpointがすべてのミドルウェアとコントローラーで正常にヒットすることを詳しく説明します。しかし、ミドルウェアのいずれも、リクエストのストリーム関連のものを読み取ることができないようです:

context.Request variable problems

context.Request.Body errors

問題が発生している場所を教えてください。どうもありがとう!

10
FreshDev

[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
Mark Hughes

これは私にとってはうまくいきます:

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

マーク・ヒューズの答えは、ある時点まで正解です。この形式のjsonを投稿した場合、{ "": "sdjklgsdjlg" }モデルバインダーは、ラッパーモデルを必要とせずに、それを単純な文字列モデルにバインドできるはずです。

3
tmg

次のようなこともできます:

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

またはユーザー[FromQuery]と直接クエリ文字列値を渡します。

1
Luca Ghersi

私はここで遅れていますが、正確な理由を共有して、他のユーザーが正確な情報を入手できるようにしたいと考えています。

データを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"]
1
Prateek Pandey

すべての依存関係の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"