首页 > 解决方案 > 带有文件和字典的 AspNetCore3 多部分帖子未按预期工作

问题描述

我的 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();
        }

任何人都知道为什么默认反序列化不起作用?

标签: c#asp.net-coreasp.net-core-webapi

解决方案


这取决于您如何提出发布请求。如果您使用的是 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);
        }
    }
}

然后

public async Task<ActionResult> UploadAttachment(
  [FromRoute] string id, 
  IFormFile file, 
  [FromForm][ModelBinder(typeof(DictionaryBinder))] Dictionary<string, string> metadata)

推荐阅读