我的asp.net核心后端服务器中有一条更新路由
[HttpPatch("{id}")]
public async Task<IActionResult> Update([FromForm] GearItemViewModel gearItem)
{
...
}
从我的角度应用程序中,我正在发送包含FormData的请求。 FormData有两个对象,一个称为“ gearImages”,另一个称为“ gearItem”。
this.selectedFileFormData.append(
"gearItem",
JSON.stringify({ id: 1, name: "tst", price: 30, inStock: false })
);
for (let index = 0; index < 3; index++) {
this.selectedFileFormData.append("gearImages", filesObj[index]);
}
当我发出以下请求时:
return this.http
.patch<GearItem>(
`${this.merchandiseUrl}/${gearItem.id}`,
gearItem.formData
)
请求到达正确的路由,但是gearItem
的参数未填充有效数据。它具有所有null
值。
当我修改接受路线时:
[HttpPatch("{id}")]
public async Task<IActionResult> Update([FromForm] List<IFormFile> gearImages)
{
...
}
该参数已成功填充。
我可以从请求对象手动反序列化gearItem对象:
JsonConvert.DeserializeObject<GearItemViewModel>(Request.Form["gearItem"]);
任何想法为什么这可能行不通?
答案 0 :(得分:1)
您的第一个动作方法是
公共异步任务更新([FromForm] GearItemViewModel gearItem)
通常,它将接受application/x-www-form-urlencoded
或multipart/form-data
。但是,在使用application/x-www-form-urlencoded
时,您不能同时发送图像文件(除非您对图像文件进行编码,例如base64
,但这并不好)。由于相同的原因,您无法在application/json
中发送有效载荷。
这意味着您的操作方法需要 multipart/form-data
中的数据,如下所示:
POST /.../Update HTTP/1.1 Content-Type: multipart/form-data; boundary=----My.Boundary ------My.Boundary Content-Disposition: form-data; name="id" 1 ------My.Boundary Content-Disposition: form-data; name="name" tst ------My.Boundary Content-Disposition: form-data; name="price" 30 ------My.Boundary Content-Disposition: form-data; name="inStock" false ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="1.jpg" Content-Type: application/octet-stream {bytes-of-your-image1} ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="2.jpg" Content-Type: application/octet-stream {bytes-of-your-image2} ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="3.jpg" Content-Type: application/octet-stream {bytes-of-your-image3} ------My.Boundary--
但是,您发送到服务器的是:
POST /.../Update HTTP/1.1 Content-Type: multipart/form-data; boundary=----My.Boundary ------My.Boundary Content-Disposition: form-data; name="gearItem" { "id": 1, "name": "tst", "price": 30, "inStock": false } ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="1.jpg" Content-Type: application/octet-stream {bytes-of-your-image1} ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="2.jpg" Content-Type: application/octet-stream {bytes-of-your-image2} ------My.Boundary Content-Disposition: form-data; name="gearImages"; filename="3.jpg" Content-Type: application/octet-stream {bytes-of-your-image3} ------My.Boundary--
结果,服务器端没有gearItem
。
假设您的GearItemViewModel
是:
public class GearItemViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool InStock { get; set; }
public IList<IFormFile> GearImages {get;set;}
}
您需要按以下方式构造FormData(我只需稍加更改即可复制并粘贴您的代码)
this.selectedFileFormData.append("id","1");
this.selectedFileFormData.append("name","tst");
this.selectedFileFormData.append("price","30");
this.selectedFileFormData.append("inStock","false");
for (let index = 0; index < 3; index++) {
this.selectedFileFormData.append("gearImages", this.filesObj[index]);
}
或者您可以使用表单元素初始化FormData
:
var formElement = document.getElementById("yourFormId");
var selectedFileFormData= new FormData(formElement);
然后发送FormData
,您将自动获得有效载荷:
this.http.patch<GearItem>(`${this.merchandiseUrl}/${gearItem.id}`, this.selectedFileFormData)
.subscribe(res => {
...
})
[编辑]
您是否知道是否可以使用formData并附加一个表示“尺寸”的对象
假设Size
和GearSize
的形状是:
// typescript
enum Size { NONE = 0, XS = 1, S = 2, XXL = 6 }
interface GearSize
{
id : Number,
available: boolean,
color : string,
size: Size,
}
假设您有4个gearSizes:
var gearSizes: GearSize[] = [
{id:1,available:true, color:"red",size:Size.S},
{id:2,available:false, color:"blue",size:Size.XS},
{id:3,available:true, color:"green",size:Size.XXL},
{id:4,available:true, color:"yellow",size:Size.NONE},
];
要发送这些gearSize,只需创建格式为sizes[index].property
的字段即可:
// a helper function that appends its fields to formdata
appendOneGearSize(formData: FormData, index: Number, size:GearSize){
formData.append(`sizes[${index}].id`,size.id.toString());
formData.append(`sizes[${index}].available`,size.avaiable.toString());
formData.append(`sizes[${index}].color`,size.color.toString());
formData.append(`sizes[${index}].size`,size.size.valueOf().toString());
}
for(let index=0; index < gearSizes.length; index++){
this.appendOneGearSize(this.selectedFileFormData,index,gearSizes[index]);
}
最后,这是服务器端操作方法:
public async Task<IActionResult> Update([FromForm] GearItemViewModel gearItem)
{
...
}
答案 1 :(得分:0)
根据我对asp.net核心的经验,FromForm接受application / x-www-form-urlencoded内容.....如果要使用json,则可以改用FromBody。