web-dev-qa-db-ja.com

ASP.NET Core Web APIコントローラーでのC#7タプルの使用

これが機能する理由を知っていますか:

    public struct UserNameAndPassword
    {
        public string username;
        public string password;
    }


    [HttpPost]
    public IActionResult Create([FromBody]UserNameAndPassword usernameAndPassword)
    {
        Console.WriteLine(usernameAndPassword);
        if (this.AuthenticationService.IsValidUserAndPasswordCombination(usernameAndPassword.username, usernameAndPassword.password))
            return new ObjectResult(GenerateToken(usernameAndPassword.username));
        return BadRequest();
    }

しかし、タプルに置き換えると、これは機能しませんか?

     [HttpPost]
    public IActionResult Create([FromBody](string username, string password) usernameAndPassword) //encrypt password?
    {
        Console.WriteLine(usernameAndPassword);
        if (this.AuthenticationService.IsValidUserAndPasswordCombination(usernameAndPassword.username, usernameAndPassword.password))
            return new ObjectResult(GenerateToken(usernameAndPassword.username));
        return BadRequest();
    }

usernameAndPassword.usernameと.passwordはどちらもnullです。

コントローラーでタプルを使用することはできませんか?

16
Eric Vaughan

名前付きタプルの名前は完全に「本物」ではないため、機能しません。コンパイラが提供する構文糖がほとんどです。 ValueTuple型のセットを見ると、名前付きタプルがそれによって表され、Item1Item2などのプロパティがあることがわかります。

コンパイラーは、名前付きタプル名へのすべての参照を実際の名前(Item1など)に書き換えます。たとえば、あなたはこれを持っています:

static void Create((string username, string password) usernameAndPassword) {
    Console.WriteLine(usernameAndPassword.username);
    Console.WriteLine(usernameAndPassword.password);
}

しかし、それをコンパイルすると、実際には次のようになります。

static void Create([TupleElementNames(new string[] {"username", "password"})] ValueTuple<string, string> usernameAndPassword)
{
  Console.WriteLine(usernameAndPassword.Item1);
  Console.WriteLine(usernameAndPassword.Item2);
}

名前はメタデータ属性TupleElementNamesにのみ含まれ、コードには含まれなくなりました。

そのため、次のような投稿をすると、

{"username": "x", "password": "y"}

あなたの行動に、asp.netはバインドできません。しかし、投稿する場合:

{"item1": "x", "item2": "y"}

その後、問題なくバインドします。おそらくTupleElementNames属性を使用できるカスタムバインダーを作成できますが、実際にはそうする必要はありません。コメントで提案されているように、個別のパラメータまたは実際のモデルを使用してください。アクション入力パラメーターは使い捨てのものではありません。後でそれらを検証したり、モデルからドキュメントを生成したりすることができます。

17
Evk

this パッケージを使用できます。このパッケージは、json本体をモデルにバインドします。

Github Repo

Installation

//Nuget
Install-Package M6T.Core.TupleModelBinder -Version 1.0.0

//dotnet cli
dotnet add package M6T.Core.TupleModelBinder --version 1.0.0

使用法

のようなstartup.csを変更します

using M6T.Core.TupleModelBinder;
....

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc(options =>
  {
      options.ModelBinderProviders.Insert(0, new TupleModelBinderProvider());
  });
}

投稿リクエスト本文

{
  "user" : {
    "Name":"Test",
    "Surname":"Test2",
    "Email":"[email protected]"
  },
  "someData" : "If you like it, you put a data on it"
}

そしてあなたのコントローラーでそれを次のように使用してください

[HttpPost]
public IActionResult CreateUser((User user, string someData) request)
{
    using (var db = new DBContext())
    {
        var newUser = db.Users.Add(request.user);
        db.SaveChanges();
        return Json(new { userId = request.user.Id, someData = request.someData});
    }
}
5
Alper Tokcan