如何在同一个模型中通过模型绑定来利用FromBody和FromRoute

问题描述 投票:0回答:1

我正在尝试将 FromRoute 用于模型的一个属性,并将 FromBody 用于其余项目,因为 API 接受 JSON。我的代码如下:

    [HttpPost("{state_id}/StateContact")]
    [Authorize]
    [OktaAllowedRoles(["arms-dmcp-user", "arms-oact-user", "arms-approver"])]
    [EnableRateLimiting("api")]
    public async Task<IActionResult> AddStateContact(AddStateContactDTO addStateContactDTO)
    {
        try
        {
            return Ok(addStateContactDTO);
        }
        catch(Exception ex)
        {
            return Ok(ex);
        } 
    }

我的模型如下:

    public class AddStateContactDTO 
{
    [FromRoute(Name = "state_id")]
    public int StateId {get; set;}

    [FromBody]
    [ModelBinder(Name = "first_name")]
    public string? FirstName {get; set;}

    [FromBody]
    [ModelBinder(Name = "last_name")]
    public string? LastName {get; set;}

    [FromBody]
    [ModelBinder(Name = "email_address")]
    [Required]
    [EmailAddress(ErrorMessage = "The Email address submitted is not a valid e-mail address.")]
    public required string EmailAddress {get; set;}
}

我的要求如下:

  const submitAddNewStateContact = () => {
if(addStateContactValid.value) {
  const json = {
    first_name : newStateContactFirstNameModel.value,
    last_name : newStateContactLastNameModel.value,
    email_address : newStateContactEmailAddressModel.value
  }

  let form = new FormData();
  form.append('first_name' , JSON.stringify(newStateContactFirstNameModel.value))
  form.append('last_name' , JSON.stringify(newStateContactLastNameModel.value))
  form.append('email_address' , JSON.stringify(newStateContactEmailAddressModel.value))

  api.post('/states/'+stateModel.value!.state_id+'/StateContact', json, config).then(response => {})
}

}

使用 json 数据进行 POST 会导致以下错误:

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
    "$": [
        "The JSON value could not be converted to System.String. Path: $ | LineNumber: 0 | BytePositionInLine: 1.",
        "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.",
        "The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
    ],
    "email_address": [
        "The EmailAddress field is required."
    ]
},
"traceId": "00-bcbe8b4460713f9266f5d6bbc15b940a-1746bfdbf5ba5213-00"

}

但是,如果我要把我的模型变成这样:

        [HttpPost("{state_id}/StateContact")]
    [Authorize]
    [OktaAllowedRoles(["arms-dmcp-user", "arms-oact-user", "arms-approver"])]
    [EnableRateLimiting("api")]
    public async Task<IActionResult> AddStateContact([FromForm] AddStateContactDTO addStateContactDTO)
    {
        try
        {
            return Ok(addStateContactDTO);
        }
        catch(Exception ex)
        {
            return Ok(ex);
        } 
    }

    public class AddStateContactDTO 
{
    [FromRoute(Name = "state_id")]
    public int StateId {get; set;}

    [ModelBinder(Name = "first_name")]
    public string? FirstName {get; set;}

    [ModelBinder(Name = "last_name")]
    public string? LastName {get; set;}

    [ModelBinder(Name = "email_address")]
    [Required]
    [EmailAddress(ErrorMessage = "The Email address submitted is not a valid e-mail address.")]
    public required string EmailAddress {get; set;}
}

所以基本上切换到使用 FromForm 和 POSTing 表单数据,然后一切都按其应有的方式绑定。但是,我希望选择以 json 形式发送数据而不发送表单数据,并且还使用 FromRoute 作为模型的某些参数,但这似乎不可能。这是一个错误还是无法一起使用 FromRoute 和 FromBody?

c# asp.net-core asp.net-core-webapi model-binding
1个回答
0
投票

根据

[FromBody]
属性:

  • [FromBody]
    应用于复杂类型参数时,应用于其属性的任何绑定源属性都将被忽略。
  • 输入格式化程序仅读取正文,不理解绑定源属性。
  • 请勿将
    [FromBody]
    应用于每个操作方法的多个参数。一旦输入格式化程序读取请求流,就无法再读取它来绑定其他
    [FromBody]
    参数。

因此,您必须将操作方法签名更改为:

public async Task<IActionResult> AddStateContact([FromRoute(Name = "state_id")] int stateId, [FromBody] AddStateContactDTO addStateContactDTO)
{
    addStateContactDTO.StateId = stateId;

    ...
}
public class AddStateContactDTO 
{
    public int StateId {get; set;}

    [ModelBinder(Name = "first_name")]
    public string? FirstName {get; set;}

    [ModelBinder(Name = "last_name")]
    public string? LastName {get; set;}

    [ModelBinder(Name = "email_address")]
    [Required]
    [EmailAddress(ErrorMessage = "The Email address submitted is not a valid e-mail address.")]
    public required string EmailAddress {get; set;}
}
© www.soinside.com 2019 - 2024. All rights reserved.