Using a C# 7 tuple in an ASP.NET Core Web API Controller

后端 未结 2 1946
别跟我提以往
别跟我提以往 2020-12-03 17:16

Do you know why this works:

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


    [HttpPost         


        
相关标签:
2条回答
  • 2020-12-03 17:43

    It doesn't work because named tuple names are not quite "real", it's mostly syntax sugar provided by compiler. If you look at ValueTuple set of types, by which named tuples are represented, you will see that they have properties like Item1, Item2 and so on.

    Compiler will rewrite all your references to named tuple names to their real names (Item1 etc). For example you have this:

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

    But when you compile that, what you really will have is this:

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

    Your names are now only in metadata attribute TupleElementNames, but not in code.

    For that reason, when you post something like:

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

    to your action, asp.net cannot bind. But if you would post:

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

    then it will bind with no problems. You can write custom binder probably, which can use TupleElementNames attribute, but there is no reason to really. Just use separate parameters or real model as suggested in comments. Your action input parameters is not some throwaway thing. You might later want to validate them, generate documentation from the model and so on.

    0 讨论(0)
  • 2020-12-03 17:49

    You can use this package. This package binds json body to your models.

    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
    

    Usage

    Modify startup.cs like

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

    Post request body

    {
      "user" : {
        "Name":"Test",
        "Surname":"Test2",
        "Email":"example@example.com"
      },
      "someData" : "If you like it, you put a data on it"
    }
    

    And in your controller use it like

    [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});
        }
    }
    
    0 讨论(0)
提交回复
热议问题