我正在使用.NET Core 7.0。我在 API 控制器中有这个端点:
[HttpPost("add")]
public string Add([FromForm] LevelData level)
{
return "";
}
这是该方法接收的类:
public class LevelData
{
//
public List<IFormFile> NewImageFiles{ get; set; } = new();
public string HomePlanId { get; set; } = "";
public SecondLevel Level { get; set; } = new SecondLevel();
}
public class SecondLevel
{
public string HomePlanId2 { get; set; } = "";
}
无论我使用 swagger 页面还是使用 ajax 调用,我总是让所有属性为空
curl -X 'POST' \
'https://localhost:7018/api/Level/add' \
-H 'accept: text/plain' \
-H 'Content-Type: multipart/form-data' \
-F 'HomePlanId=1' \
-F 'Level.HomePlanId2=2'
var formData = new FormData();
// Append the properties of the LevelData object
formData.append('HomePlanId', 'your_home_plan_id');
formData.append('Level.HomePlanId2', 'your_home_plan_id_2');
// Make the AJAX call to the C# API
$.ajax({
url: '/api/level/add',
type: 'POST',
contentType: false,
processData: false
data: formData,
success: function (data) {
// Handle the API response here if needed
console.log("API response:", data);
},
error: function (error) {
// Handle errors here if the API call fails
console.error("API error:", error);
}
});
我想使用 FromForm 来传递 FormFile(图像)。
我测试了评论这部分
public SecondLevel Level { get; set; } = new SecondLevel();
当被注释掉时,代码就可以工作了。
我需要更改什么才能正确设置所有属性,包括
SecondLevel
修改参数名称:
[HttpPost("add")]
//level=>levelData
public string Add([FromForm] LevelData levelData)
{
return "";
}
您必须避免将参数命名为与嵌套模型属性相同的名称
啊MVC绑定,我真的不喜欢这种默认行为。
当绑定顶级对象时,例如控制器属性或函数参数,绑定器将首先查找具有相同名称的提交值。
如果找到具有该名称的值,则该对象的子属性或集合将与该前缀绑定。
因为在您的情况下,您的参数称为
level
并且您提交的值以 Level
开头。那么binder就期待你提交;
Level.HomePlanId=your_home_plan_id&Level.Level.HomePlanId2=your_home_plan_id_2
然后,如果没有找到具有相同名称的值,绑定器将尝试绑定没有前缀的对象。因此,如果您将您的论点重命名为其他内容,您可以提交;
HomePlanId=your_home_plan_id&Level.HomePlanId2=your_home_plan_id_2
但是如果客户端提交了一个与你的变量同名的额外值,那么绑定将会失败。
当您的顶级对象包含
Dictionary<>
并且您尝试提交空集合时,我发现这种行为特别烦人。在本例中,您为另一个顶级对象提交的任何其他值都将作为键添加到字典中。
您可以通过向每个参数添加显式绑定前缀来覆盖此行为。或者通过定义自定义
IBindingMetadataProvider
进行全局设置。
public class BindingProvider : IBindingMetadataProvider {
public void CreateBindingMetadata(BindingMetadataProviderContext context)
{
IModelNameProvider nameAttrib = null;
if (context.BindingMetadata.BinderModelName == null
&& context.BindingMetadata.IsBindingAllowed
&& (nameAttrib = context.Attributes.OfType<IModelNameProvider>().FirstOrDefault())!=null
&& nameAttrib.Name == null)
context.BindingMetadata.BinderModelName =
context.Key.PropertyInfo?.Name
?? context.Key.ParameterInfo?.Name;
}
}
services.AddMvc(o => o.ModelMetadataDetailsProviders.Add(new BindingProvider()));