web-dev-qa-db-ja.com

.Net Core MVCでDTOクラスを使用せずに、POST APIで複数のパラメーターを渡す

APIを呼び出すアクションがWebプロジェクトにあります

    [HttpPost]
    public async Task<IActionResult> ExpireSurvey(int id)
    {
        var token = await HttpContext.GetTokenAsync("access_token");

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

            var path = "/api/forms/ExpireSurvey";
            var url = Domain + path;
            var data = JsonConvert.SerializeObject(id);
            HttpContent httpContent = new StringContent(data, Encoding.UTF8, "application/json");
            var response = await client.PutAsync(url, httpContent);

            return Json(response);
        }
    }

APIプロジェクトでは、これは次のように受信されます。

[HttpPut]
    public IActionResult ExpireSurvey([FromBody] int surveyId)
    {
        _repository.ExpireSurvey(surveyId, expiryDate);
        return Ok();
    }

これは正常に動作しますが、int idとDateTime変数を渡したい場合、どのようにシリアル化して両方をHttpContentに渡しますか? DTOオブジェクトでそれを行うことができますが、フィールドが2つしかないときにDTOオブジェクトをセットアップしたくありません。

6
egmfrs

このような匿名型を使用できます

var x = new { id = 2, date = DateTime.Now };
var data = JsonConvert.SerializeObject(x);

データを受信するときは、[FromBody]パラメータを1つだけ持つことができます。したがって、それは複数のパラメーターを受け取る場合には機能しません(URLに1つを除くすべてを入れることができない場合を除く)。 DTOを宣言したくない場合は、次のような動的オブジェクトを使用できます。

[HttpPost]
public void Post([FromBody] dynamic data)
{
    Console.WriteLine(data.id);
    Console.WriteLine(data.date);
}

ただし、匿名型と動的変数を無理に使用しないでください。これらはJSONを操作するのに非常に便利ですが、すべての型チェックが失われるため、C#を操作するのに非常に便利です。

8
Hans Kilian

ASP.NET CoreはRESTベースであり、RESTは基本的にresourcesの概念を扱います)であることを認識すると役立つと思います。一般的な考え方は、ここではDTOと呼んでいるものを用意する必要があるということです。つまり、明確で無関係なデータのビットを投稿するのではなく、何かを表すobjectを投稿します。

これは、Swaggerなどを混ぜてAPIのドキュメントを生成する場合にますます重要になります。作成したオブジェクトはそのドキュメントの一部になり、APIの利用者にアプリの開発をフォローするためのテンプレートを提供します。

長くても短くても、リソース/オブジェクト/ DTO /その他の概念を採用すると思います。 モデル APIが使用するデータ。これは、APIの開発者として、およびAPIのコンシューマーの両方に役立ちます。

5
Chris Pratt

以下の例のように、URLとして複数のパラメータを渡すことができます

パラメータ名は同じである必要があります(大文字と小文字は区別されません)。名前が一致しない場合、パラメータの値は設定されません。

[HttpPost]
[Route("{surveyId}/{expiryDate}")]
public IActionResult Post(int surveyId, DateTime expiryDate)
{
    return Ok(new { surveyId, expiryDate });
}

呼び出しURL

http://localhost:[port]/api/[controller]/1/3-29-2018
5
ElasticCode

辞書でそれができる

Dictionary<string, object> dict = new Dictionary<string, object>();
dict["id"] = 1
dict["date"] = DateTime.Now;

JsonConvert.SerializeObject(dict);
0
Steve

上記の回答に基づいて、私は次のコードを機能させました。これが誰かを助けることを願っています! (もちろん私を正しい軌道に乗せてくれた他の人に感謝します)

/// <summary>
/// Post api/dostuff/{id}
[HttpPost]
[Route("dostuff/{id}")]
public async Task<IActionResult> DoStuff([FromBody]Model model, int id)
{
    // Both model and id are available for use!
}
0
Ross