C# AspNetCore3包含文件和字典的多部分post未按预期工作

C# AspNetCore3包含文件和字典的多部分post未按预期工作,c#,asp.net-core,asp.net-core-webapi,C#,Asp.net Core,Asp.net Core Webapi,在我的AspNetCore3控制器中有一个post方法,它接受一个文件和一个包含元数据的字典。我遇到的问题是字典不是自动反序列化的,我必须手动反序列化 /// <summary>Upload an attachment</summary> [HttpPost("{id}")] [DisableRequestSizeLimit] public async Task<ActionResult> Upl

在我的AspNetCore3控制器中有一个post方法,它接受一个文件和一个包含元数据的字典。我遇到的问题是字典不是自动反序列化的,我必须手动反序列化

        /// <summary>Upload an attachment</summary>
        [HttpPost("{id}")]
        [DisableRequestSizeLimit]
        public async Task<ActionResult> UploadAttachment(
            [FromRoute] string id, 
            IFormFile file, 
            [FromForm] Dictionary<string, string> metadata)
        {
            // TODO figure out why the metadata isn't loaded/deserialized from the form data
            Dictionary<string, string> dict = null;
            if (Request.Form.TryGetValue(nameof(metadata), out var values))
            {
                try
                {
                    dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(values);
                }
                catch { /* ignore */ }
            }

            await m_service.UploadAttachment(id, file, dict);
            return Ok();
        }
///上传附件
[HttpPost(“{id}”)]
[DisableRequestSizeLimit]
公共异步任务上载附件(
[FromRoute]字符串id,
格式化文件,
[FromForm]字典元数据)
{
//TODO找出元数据没有从表单数据加载/反序列化的原因
字典dict=null;
if(Request.Form.TryGetValue(nameof(元数据),out var值))
{
尝试
{
dict=JsonConvert.DeserializeObject(值);
}
捕获{/*忽略*/}
}
等待m_服务。上传附件(id、文件、dict);
返回Ok();
}

有人知道为什么默认反序列化不起作用吗?

这取决于您如何发出post请求。如果您使用的是Postman,那么根据UploadAttachment()操作签名,它应该是这样的

以下是原始或请求:

POST / HTTP/1.1
Host: localhost:62117
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Host: localhost:62117
Content-Length: 294    

Content-Disposition: form-data; name="metadata[key1]"

value1
------WebKitFormBoundary7MA4YWxkTrZu0gW--,
Content-Disposition: form-data; name="metadata[key1]"

value1
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Content-Disposition: form-data; name="metadata[key2]"

value2
------WebKitFormBoundary7MA4YWxkTrZu0gW--
如果您想像这样传递json内容

然后需要添加自定义模型绑定器

public class DictionaryBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        if (bindingContext.HttpContext.Request.HasFormContentType)
        {
            var form = bindingContext.HttpContext.Request.Form;
            var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(form[bindingContext.FieldName].ToString());
            bindingContext.Result = ModelBindingResult.Success(data);
        }
    }
}
公共类字典binder:IModelBinder
{
公共异步任务BindModelAsync(ModelBindingContext bindingContext)
{
if(bindingContext==null)
{
抛出新ArgumentNullException(nameof(bindingContext));
}
if(bindingContext.HttpContext.Request.HasFormContentType)
{
var form=bindingContext.HttpContext.Request.form;
var data=JsonConvert.DeserializeObject(形式为[bindingContext.FieldName].ToString());
bindingContext.Result=ModelBindingResult.Success(数据);
}
}
}
然后

公共异步任务上传附件(
[FromRoute]字符串id,
格式化文件,
[FromForm][ModelBinder(typeof(DictionaryBinder))]字典元数据)

对于邮递员来说,这确实有效,但斯威格构建了这篇文章,但这不起作用:
curl-X post”http://localhost:5000/api/Items/123“-H”接受:*/*“-H”授权:承载xxxx“-H”内容类型:多部分/表单数据“-F”元数据={“additionalProp1”:“字符串”,“additionalProp2”:“字符串”,“additionalProp3”:“字符串”}”-F“file=@pasfoto.jpg;type=image/jpeg“
因为要将json传递给元数据,所以需要像上面这样的自定义模型绑定器
public async Task<ActionResult> UploadAttachment(
  [FromRoute] string id, 
  IFormFile file, 
  [FromForm][ModelBinder(typeof(DictionaryBinder))] Dictionary<string, string> metadata)