在ASP.NET Core Web API Controller中使用C#7元组

Eri*_*han 13 c# tuples asp.net-core c#-7.0 asp.net-core-webapi

你知道为什么会这样吗:

    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();
    }
Run Code Online (Sandbox Code Playgroud)

但是当我用元组替换它时,这不起作用?

     [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();
    }
Run Code Online (Sandbox Code Playgroud)

usernameAndPassword.username和.password都为null.

你不被允许在控制器中使用元组吗?

Evk*_*Evk 15

它不起作用,因为命名的元组名称不是很"真实",它主要是由编译器提供的语法糖.如果查看ValueTuple表示名称元组的类型集,您将看到它们具有类似的属性Item1,Item2依此类推.

编译器会将对命名元组名称的所有引用重写为它们的真实名称(Item1等).例如,你有这个:

static void Create((string username, string password) usernameAndPassword) {
    Console.WriteLine(usernameAndPassword.username);
    Console.WriteLine(usernameAndPassword.password);
}
Run Code Online (Sandbox Code Playgroud)

但是当你编译它时,你真正拥有的是:

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

您的名称现在仅在元数据属性中TupleElementNames,但不在代码中.

出于这个原因,当你发布类似的东西:

{"username": "x", "password": "y"}
Run Code Online (Sandbox Code Playgroud)

对你的行动,asp.net无法绑定.但如果你发布:

{"item1": "x", "item2": "y"}
Run Code Online (Sandbox Code Playgroud)

然后它会没有任何问题.您可以编写自定义绑定器,它可以使用TupleElementNames属性,但没有理由真正.只需使用评论中建议的单独参数或实际模型.你的动作输入参数并不是一件容易的事.您可能稍后想要验证它们,从模型生成文档等等.


小智 11

你可以使用这个包。此包将 json 正文绑定到您的模型。

Github 仓库

安装

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

//dotnet cli
dotnet add package M6T.Core.TupleModelBinder --version 1.0.0
Run Code Online (Sandbox Code Playgroud)

用法

修改startup.cs之类的

using M6T.Core.TupleModelBinder;
....

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

发布请求正文

{
  "user" : {
    "Name":"Test",
    "Surname":"Test2",
    "Email":"example@example.com"
  },
  "someData" : "If you like it, you put a data on it"
}
Run Code Online (Sandbox Code Playgroud)

在你的控制器中使用它

[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});
    }
}
Run Code Online (Sandbox Code Playgroud)