【问题标题】:How to send IFormFile to Web API as part of ViewModel object如何将 IFormFile 作为 ViewModel 对象的一部分发送到 Web API
【发布时间】:2018-08-11 09:20:19
【问题描述】:

我有带有以下控制器的 .NET Core Web 应用程序:

    [HttpPost]
    public async Task<IActionResult> Update(StudentDetailsViewModel vm)
    {           
        var tokenNo = HttpContext.Session.GetString("Token");
        vm.ID = Convert.ToInt32(HttpContext.Session.GetString("StudentId"));

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenNo);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        var putStudentUrl = _appSettings.Value.Apis.GSRTCApi.Url + _appSettings.Value.Apis.GSRTCApi.StudentsEndpoint + vm.ID;

        var settings = new JsonSerializerSettings();

        var stringData = JsonConvert.SerializeObject(vm); 

        var contentData = new StringContent(stringData, Encoding.UTF8, "application/json");

        var response = await client.PutAsync(putStudentUrl, contentData); // contentData);


        return RedirectToAction("Index", "Home");
    }

控制器调用我的 Web API 并且一切正常,直到我通过我的 html 表单上传文件。发生这种情况时,会在客户端的 StudentDetailsViewModel 的 IFormFile 属性中获取文件,但在进行 API 调用时,整个对象为空。 API 控制器是:

[HttpPut("{id}")]
public async Task<IActionResult> Put(int? id, [FromBody]StudentViewModel student)
{
    // API operations here
} 

我怀疑我没有正确序列化 StudentDetailsViewModel 对象,因为我有一个属性 IFormFile,它是一个接口。但是,我不确定我需要如何自定义 Json.Newsoft 对象。

【问题讨论】:

  • 包含模型并调用JS。
  • 我没有JS代码只是一个带有asp标签的表单

标签: rest api .net-core asp.net-core-2.0


【解决方案1】:

要发送IFormFile,您需要使用FromForm,这是删除FromBodyMultipartFormDataContent 时的默认值。

以下是完整的步骤:

  1. Web 应用模型
public class StudentDetailsViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IFormFile File { get; set; }
}
  1. Web 应用控制器
public async Task<IActionResult> Update(StudentDetailsViewModel vm)
{

    HttpClient client = new HttpClient();
    var putStudentUrl = @"url";
    byte[] data;
    using (var br = new BinaryReader(vm.File.OpenReadStream())) 
    {
        data = br.ReadBytes((int)vm.File.OpenReadStream().Length);
    }
    ByteArrayContent bytes = new ByteArrayContent(data);
    MultipartFormDataContent multiContent = new MultipartFormDataContent();
    multiContent.Add(bytes, "file", vm.File.FileName);
    multiContent.Add(new StringContent(vm.Id.ToString()),"Id");
    multiContent.Add(new StringContent(vm.Name), "Name");
    var response = await client.PutAsync(putStudentUrl, multiContent); 
    return RedirectToAction("Index", "Home");
}
  1. Web API 模型
public class StudentViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IFormFile File { get; set; }
}
  1. Web API 控制器
[HttpPut("{id}")]
public async Task<IActionResult> Put(int? id,StudentViewModel student)
{
    using (var stream = new FileStream(@"file path", FileMode.Create))
    {
        await student.File.CopyToAsync(stream);
    }
    return Ok();
}

注意multiContent.Add(bytes, "file", vm.File.FileName);,第二个参数是IFormFile字段的名称。

【讨论】:

  • 我有一个虚拟对象属性作为模型的一部分,当我使用 [FromForm] 而不是 [FromBody] 时,我无法将其发送到 API。此外,这对我来说似乎不是一个非常优雅的解决方案,因为我需要将每个属性都添加到 multiContent。
  • 不适合我。我的 API 控制器上出现 415 不受支持的媒体类型。
  • multiContent.Add(bytes, "file", vm.File.FileName); - 为我工作,它是 ByteArrayContent 而不是 StreamContent。虽然不确定StreamContent 是否也能正常工作。
猜你喜欢
  • 2020-02-05
  • 2014-12-19
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多