dotnet core 从表单数据中获取字典

dotnet core get dictionairy from form data

如何从 form-data 获得 Dictionairy<string, string>

查看模型:

public class SubmitRequestModel
{
  public Dictionairy<string, string> InputFields { get; set; }
 
  public List<IFormFile> Attachments { get; set; }
}

操作:

[HttpPut("{id:int}")]
public async Task<IActionResult> Submit(int id, [FromForm] SubmitRequestModel model)
{
  // model.InputFields is initialized but it's count is 0
  // do whatever
}

这是一个 API 控制器。与 cshtml 或剃刀无关。

所以 model.InputFields 不是 null,但它的计数是 0。当我查看原始请求时。我可以看到输入已收到,但未绑定到模型中的字典。

Request.Form 集合的值:https://prnt.sc/11x532p

我需要使用表单数据,因为我们正在根据请求上传文件。这需要 multipart/form-data.

如何将数据成功解析为模型?


关于我如何测试的信息:

我有 swagger 设置。我将生成的 Swagger OpenAPI json 导入到 Postman 中并以这种方式进行测试。我相信这应该是 Swagger 生成的正确请求。但我不确定它是否以正确的方式格式化字典。这将是 JSON 数据请求的正确方法。但我不确定这是否适用于此。

我觉得你的问题和给定的link是一样的,直接过一遍link可能对你有帮助。

Bind dynamic form data

所以一种解决方案(这不是我最喜欢的但它有效)是手动解析字典。

行动的第一件事:

if (model.InputFields == null || model.InputFields.Count == 0)
{
    var rawInputFields = Request.Form["InputFields"].ToString();
    model.InputFields = JsonSerializer.Deserialize<Dictionary<string, string>>(rawInputFields);
}

您可以通过自定义实现此目的 IModelBinder:

public class DictionaryBinder<TKey, TValue> : IModelBinder
{
    public 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 = JsonSerializer.Deserialize<Dictionary<TKey, TValue>>(form[bindingContext.FieldName]);
            bindingContext.Result = ModelBindingResult.Success(data);
        }

        return Task.CompletedTask;
    }
}

模型class将变为:

public class SubmitRequestModel
{
    [FromForm]
    [ModelBinder(BinderType = typeof(DictionaryBinder<string, string>))]
    public Dictionary<string, string> InputFields { get; set; }

    public List<IFormFile> Attachments { get; set; }
}