.Net Core WebAPI 傳值到後端Controller的方法

網頁功能最常用的就是資料間的傳遞,不管事表單資料傳送到後台,或者是輸入查詢資料後,由後端DB回傳資料。這之間都少不了傳輸資料到後台。
在以前MVC的時候,可以透過Razor語法的HTML Helper的BeginForm,在Submit之後,會透過ModelBinding把資料傳到後端Controller。
或是在View直接把整個Form序列化(serilizeArray)後再傳給後端。
現再寫前後分離(Angular + .Net 6 WebAPI)採用WebAPI來開發,剛完成第一個前後分離專案,順便把資料傳送到Controller的方式記錄下來。

  • Post整個表單資料

先來看看類似以前MVC最常用到的POST表單資料到後端Controller,在WebAPI裡要如何處理:

HTML:

<form method="post" #frm="ngForm" [formGroup]="testForm" (ngSubmit)="onSubmit()">
  <div class="form-row">
    <label><span class="label-font">姓名:</span></label><input formControlName="name" type="text">
  </div>
  <div class="form-row">
    <label><span class="label-font">年齡:</span></label><input formControlName="age" type="text">
  </div>
  <input type="submit" value="SUBMIT">
</form>
  • HTML裡面的input都要給他一個formControlName跟TS的FormGroup做對應,不然到時候Angular建置時會報


TS:

export class TestComponent implements OnInit {

  public testForm: FormGroup = new FormGroup({
    name: new FormControl(),
    age: new FormControl()
  })

  constructor(
    private _httpClient: HttpClient
  ) { }

  ngOnInit(): void {
  }

  onSubmit(frm: any) {
    const url = "/Test/Method_1";
    let params = {
      name: this.testForm.controls["name"].value.toString(),
      age: this.testForm.controls["age"].value.toString(),
      ids: [1,2,3,4,5]
    };
    
    /*也可以這樣寫*/
    //let params = this.testForm.value;
    /*也可以這樣寫 ref:https://www.simplilearn.com/tutorials/angular-tutorial/angular-service*/
    //let params = frm.value;
    
    let options =
    {
      //headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
      withCredentials: true
    };

    this._httpClient.post(url, params, options).subscribe();
  }
}
  • params可以直接寫成let params = this.testForm.value;,這樣就不用一個一個塞值到object的property裡了。
  • 如果post的參數給的是object物件,header的Content-Type再Angular會預設為'application/json',會自動把表單內容序列化後post給後端,Action的參數要加上[FromBody]的標籤,才能成功接到參數。
參數使用object
參數使用object,Content-Type為application/json

 

  • 如果是formData的話,header的Content-Type會由Angular預設的application/json變更為'multipart/form-data',Action的參數要加上[FromBody]的標籤,才能成功接到參數。雖然參考2.的內容是說 Form Post預設是使用application/x-www-form-urlencoded,但我測試後參數如果為FormData,Angular好像預設會使用multipart/form-data。如果傳送的是multipart/form-data但Action參數加的是[FromBody]是會報錯的(下圖3.)
參數使用FormData
參數使用FormData,Content-Type為multipart/form-data
參數使用FormData,但Action的參數加上[FromBody]標籤會報錯誤訊息
  • d

 

Controller:

        [HttpPost]
        public async Task<IActionResult> Method_1([FromBody] Object_Test data)
        {            
            try
            {
                return Ok(new { name = $"processed_{data.Name}", age = $"processed_{data.Age}", ids = data.Ids });
            }
            catch (Exception Ex)
            {
                return BadRequest(new {errMsg = Ex.Message,  name = $"processed_{data.Name}", age = $"processed_{data.Age}" });
            }
        }
  • Controller的參數部分要加上[FromBody]的標籤,並且參數的型別要用一個Model裝起來。無法像在MVC時直接宣告一個與input name一樣的參數(ex: string name),他就會自己做model binding。[FromBody]跟[FromForm]的差別可以參考,個人是習慣用[FromBody]接整理好的Json隔是參數。
     

  • .

 

Ref:
1.What the difference between [FromForm] and [FromBody] in Asp.Net Core
2.[筆記] Postman 常見的 Content-type
3.Angular預設Content-type
4.[鐵人賽 Day09] ASP.NET Core 2 系列 - Model Binding
5.ASP.NET Core Model Binding 死活綁不上 - 1