web-dev-qa-db-ja.com

ASP.NET Core MVC:型なしで文字列にバインドされた生のJSONを取得する方法は?

this 以前のASP.NETバージョンに関する古い質問と同様に、HTTP POSTのリクエスト本文を文字列にバインドするようにしたい。メソッドはバインドしますが、ASP.NETがコントローラーメソッドを呼び出すとき、そのvalueはnullです。

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.
    }

ストリームからボディを取得する必要がありますか?または、これでうまくいくでしょうか?上記の方法をテストするとき、次のhttpヘッダーを使用しました。

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

私は次の本文を渡します:{ "a": 1 }

Aという名前の文字列変数にバインドしません。取得したJSONをバインドし、メソッド内からJSONコンテンツ(任意のコンテンツ)を使用します。

ドキュメントを理解したら、[FromBody]属性は、私が望んでいたことを行うべきでしたが、ASP.NETコアMVCバインディングメカニズムはjsonを「文字列値」にバインドしないと推測していますが、おそらく、同等のレベルを得る他の何かを行うことができます柔軟性の。

同様の質問 here は、多分私が[FromBody] dynamic dataを使用する代わりに[FromBody] string value

更新:.NETコアフレームワークでJSONとXMLエンコーディングを処理したい場合は、その機能を無効にしてしまったため、この種のトリックを実行する前に考慮する必要があります。特定の種類のREST=サーバーは、XMLとJSONの両方のコンテンツタイプをサポートするための要件を持つことができます。

43
Warren P

以下は.net core 1.xでは機能しますが、.net core 2.xでは機能しません。

私がコメントしたように、解決策は、dynamicの代わりにstringを使用して、パラメータリストとして[FromBody]dynamic dataを使用することで、JObjectを受け取ります。

注意:アーキテクチャが、コンテンツタイプヘッダーエントリに応じて、XMLとJSONの生成に同等に流singleである単一のWebApiサーバーを必要とする場合、この種類のJSONを直接消費する戦略は、逆効果になる可能性があります。 (同じサービスでXMLとJSONの両方をサポートすることで十分な作業が可能になりますが、MVCアセットパイプラインをさらに上にしたものを取り、それをコントローラーメソッドに移動します。これは、MVCの精神に反することが判明しました。 、POCOが既に解析されているためモデルが表示されます)。

メソッド内で文字列に変換したら、着信JObject(JSONのメモリデータ型のNewtonsoft.JSON)を文字列に変換します。

他の回答はこちら にあります。

Jeson Martajayaのおかげでのサンプルコード:

動的な場合:

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

JObjectを使用したサンプルコード:

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

私が見つけた最もクリーンなオプションは、独自の単純なInputFormatterを追加することです。

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

そして、ConfigureServices内のStartup.csで:

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

これにより、コントローラーで生のJSONペイロードを取得できます。

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

あるいは、JObjectをそのまま受け入れることもでき、文字列が本当に必要な場合は、直接ToString()でもLinq to Json otを使用できます。

5
Fabio Salvalai

次の2つのメソッドは、ASP.NETコア2で機能し、生のjson文字列を読み取ります。

1)これはパフォーマンスが向上しています。

    [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

サムはすでにほぼ同じことを言って下票を投じていることがわかりますが、Postmanを使用したテストでは、リクエストの本文を単純な二重引用符で囲まれた文字列ASP binds itデフォルトの「[FromBody] string value」引数で問題ありません。

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

Application/jsonがこの形式のデータを受け入れることになっているかどうかはわかりません。うまくいけば、これを投稿することで、知識のある人がパイプを送り、これが有効かどうかを述べてくれるでしょう。

0
Neutrino