使用Ajax在Asp.Net Core中上传文件

33

大家好,

我正在尝试使用ajax从客户端上传文件到服务器端(asp.net core)控制器,但是我得到了空值。

这是我的html和javascript代码:

<input type="file" id="myfile" class="required" />
<button type="button" class="btn btn-info" onclick="uploadcsvfile()">

<script>
    function uploadcsvfile() {
       var myfile= document.getElementById("myfile");
       var formData = new FormData();

       if (myfile.files.length > 0) {
           for (var i = 0; i < myfile.files.length; i++) {
               formData.append('file-' + i, myfile.files[i]);
           }
       }

       $.ajax({
           url: "/MyController/UploadFile/",
           type: "POST",
           dataType: "json",
           data: formData,
           contentType: false,
           processData: false,
           success: function(data){

           },
           error: function (data) {

           }
        })
    }
</script>

这是我的控制器,使用了 IFormFile。

public async Task<JsonResult> UploadFile(IFormFile formData)
{
      // do something here
}

提前感谢你!


{btsdaf} - Saurabh Tiwari
服务器是否期望 data: {formData:formData}?在 public async Task<JsonResult> UploadFile(IFormFile formData) 中,formData 期望是什么?Task<JsonResult> 的目的是什么? - guest271314
@guest271314 如果我使用大括号,也会得到null。 - jsonGPPD
{btsdaf} - Ahefaz
2
@jsonGPPD,您能接受一个答案吗?我刚刚尝试了Mohammed Noureldin的答案,它对我有用,那个答案对您有用吗? - David Swindells
显示剩余3条评论
6个回答

65

关于文件上传在ASP.NET Core中的可选项已经在这里很好地解释了:

浏览器端代码:

HTML

<form id="form" name="form" action="/uploader" enctype="multipart/form-data" method="post">
  <div class="buttons">
    <div class="upload-button">
      <div class="label">Click me!</div>
      <input id="files" name="files" type="file" size="1" multiple onchange="uploadFiles('files');" />
    </div>
  </div>
</form>

JavaScript

function uploadFiles(inputId) {
  var input = document.getElementById(inputId);
  var files = input.files;
  var formData = new FormData();

  for (var i = 0; i != files.length; i++) {
    formData.append("files", files[i]);
  }

  $.ajax(
    {
      url: "/uploader",
      data: formData,
      processData: false,
      contentType: false,
      type: "POST",
      success: function (data) {
        alert("Files Uploaded!");
      }
    }
  );
}

服务器端代码:


[HttpPost]
public async Task<IActionResult> Index(IList<IFormFile> files)
{
  foreach (IFormFile source in files)
  {
    string filename = ContentDispositionHeaderValue.Parse(source.ContentDisposition).FileName.Trim('"');

    filename = this.EnsureCorrectFilename(filename);

    using (FileStream output = System.IO.File.Create(this.GetPathAndFilename(filename)))
      await source.CopyToAsync(output);
  }

  return this.View();
}

private string EnsureCorrectFilename(string filename)
{
  if (filename.Contains("\\"))
    filename = filename.Substring(filename.LastIndexOf("\\") + 1);

  return filename;
}

private string GetPathAndFilename(string filename)
{
  return this.hostingEnvironment.WebRootPath + "\\uploads\\" + filename;
}

2
运行完美。 - Sunil Soni
在我的情况下,我发送的 Model 还包含其他信息,例如名字、姓氏等。public class Model { public string FirstName {get;set;} public List<IFormFile> Attachments { get; set; } }当我从 Ajax 发送时,我收到了 400 状态码。如何发布? - Sagar Patil
@SagarPatil 请发布一个关于这个问题的新问题,并将链接作为评论添加在这里,我很乐意尽力帮助。 - Mohammed Noureldin
@MohammedNoureldin,请在此处查看我的问题 https://stackoverflow.com/q/59422872/9491935 - Sagar Patil
1
你在列出最佳选项方面的创意非常棒。 - Sultan

23

这里是将文件发布到您的控制器操作的简单方法。

视图

var formData = new FormData();
formData.append('file', $('#myfile')[0].files[0]); // myFile is the input type="file" control

var _url = '@Url.Action("UploadFile", "MyController")';

$.ajax({
    url: _url,
    type: 'POST',
    data: formData,
    processData: false,  // tell jQuery not to process the data
    contentType: false,  // tell jQuery not to set contentType
    success: function (result) {
    },
    error: function (jqXHR) {
    },
    complete: function (jqXHR, status) {
    }
});

控制器:

[HttpPost]
public ActionResult UploadFile(IFormFile file)
{
    List<string> errors = new List<string>(); // added this just to return something

    if (file != null)
    {
        // do something
    }

    return Json(errors, JsonRequestBehavior.AllowGet);   
}

{btsdaf} - Neville Nazerane
{btsdaf} - jegtugado
事实是,在Asp.Net Core中,没有HttpPostedFileBase,只有IFormFile。我是否有办法获取文件? - jsonGPPD
@jsonGPPD 忘记了那个。请检查更新后的答案。 - jegtugado

3

(.Net Core) 完整的工作示例。该答案的某些部分采用了上面的答案,并修复了编译错误。

假设您想要上传文件,然后将使用已上传的文件提交表单。

Register.cshtml

@using UploadFileAjaxPostWebApp.Models.Account

@model RegisterModel

@using (Html.BeginForm("Register", "Account", FormMethod.Post))
{
  <div>
    <label>First Name </label>
    <input type="text" name="FirstName" value="John" />
  </div>
  <div>
    <label>Second Name </label>
    <input type="text" name="SecondName" value="Smith" />
  </div>
  <div>
    <label>Resume</label>
    <input type="file" id="fileUpload1" onchange="uploadFiles('fileUpload1');" />
    <input type="hidden" id="ResumeFileName" name="ResumeFileName" value="@Model.ResumeFileName" />
  </div>

  <div>
    <input type="submit" value="Submit" />
  </div>
}

<script type="text/javascript">

function uploadFiles(inputId) {
    var input = document.getElementById(inputId);
    var files = input.files;
    var formData = new FormData();

    for (var i = 0; i !== files.length; i++) {
        formData.append("files", files[i]);
    }

    $.ajax(
        {
            url: "/account/uploadfiles",
            data: formData,
            processData: false,
            contentType: false,
            type: "POST",
            success: function (data) {
                // Set the property of the Model.
                $("#ResumeFileName").val(data.fileName);
                alert("Files Uploaded! " + data.fileName);
            }
        }
    );
}
</script>
<账户控制器:>
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using UploadFileAjaxPostWebApp.Models.Account;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;

namespace UploadFileAjaxPostWebApp.Controllers
{
  public class AccountController : Controller
  {
    private readonly IWebHostEnvironment _hostEnvironment;

    public AccountController(IWebHostEnvironment hostEnvironment)
    {
        _hostEnvironment = hostEnvironment;
    }

    public IActionResult Register()
    {
        RegisterModel model = new RegisterModel();

        return View(model);
    }

    [HttpPost]
    public IActionResult Register(RegisterModel model)
    {
        // Handle your post action ....
        return View(model);
    }

    [HttpPost]
    public async Task<ActionResult> UploadFiles(IList<IFormFile> files)
    {
        string fileName = null;

        foreach (IFormFile source in files)
        {
            // Get original file name to get the extension from it.
            string orgFileName = ContentDispositionHeaderValue.Parse(source.ContentDisposition).FileName.Value;

            // Create a new file name to avoid existing files on the server with the same names.
            fileName = DateTime.Now.ToFileTime() + Path.GetExtension(orgFileName);

            string fullPath = GetFullPathOfFile(fileName);

            // Create the directory.
            Directory.CreateDirectory(Directory.GetParent(fullPath).FullName);

            // Save the file to the server.
            await using FileStream output = System.IO.File.Create(fullPath);
            await source.CopyToAsync(output);
        }

        var response = new { FileName = fileName };

        return Ok(response);
    }

    private string GetFullPathOfFile(string fileName)
    {
        return $"{_hostEnvironment.WebRootPath}\\uploads\\{fileName}";
    }
 }
}

RegisterModel类

namespace UploadFileAjaxPostWebApp.Models.Account
{
  public class RegisterModel
  {
    public string FirstName { get; set; }

    public string SecondName { get; set; }

    public string ResumeFileName { get; set; }
  }
}

2
您只需要指定文件输入的"name"属性(与ASP.NET控制器中的变量名相同)。 HTML:
<input type="file" name="thefile" />

C#:

public ActionResult UploadFile(IFormFile thefile) { }

对于 AJAX 请求,您需要在 FormData 对象中指定适当的名称。


0
var GetImages = $('[name="Images"]');
console.log(GetImages[0].files)

for (var i = 0; i != GetImages[0].files.length; i++) {
    form.append("Images", GetImages[0].files[i]);
}

你能否解释一下这段代码是如何解决问题的? - deepakchethan
虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。 - Al Foиce ѫ

0

因为参数名称不同而获取空值。

客户端: 在设置文件时,将fromData与您的操作方法参数名称相同

formData.append('formData' myfile.files[i]);

由于您正在上传CSV文件,请添加验证以仅允许CSV文件。

function uploadcsvfile() {
    var myfile= document.getElementById("myfile");
    var formData = new FormData();
    if (myfile.value.toLowerCase().lastIndexOf(".csv") == -1) 
    {
      alert("Please upload a file with .csv extension.");
      return false;
    } 
    
    // else code to upload
}

由于您正在上传多个文件

HTML:添加多个属性

<input type="file" id="myfile" class="required" multiple />

服务器端:添加 IFromFile 列表

public async Task<JsonResult> UploadFile(List<IFormFile> formData)
{
      // do something here
}

如果您没有使用表单标记,则添加 @Html.AntiForgeryToken()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接