在 ASP.NET 核心 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均为空。

是否不允许在控制器中使用元组?

它不起作用,因为命名元组名称不是很"真实",它主要是编译器提供的语法糖。如果您查看表示命名元组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属性,但没有理由真的这样做。只需按照评论中的建议使用单独的参数或真实模型即可。您的操作输入参数不是什么一次性的东西。您以后可能想要验证它们,从模型生成文档等。

您可以使用此软件包。此包将 json 正文绑定到模型。

Github Repo

安装

//Nuget
Install-Package M6T.Core.TupleModelBinder -Version 1.0.0
//dotnet cli
dotnet add package M6T.Core.TupleModelBinder --version 1.0.0

用法

修改启动.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":"example@example.com"
},
"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});
}
}

最新更新