Загрузка файла или нескольких файлов в ASP.NET MVC 2

Перевод: Phil Haack — Uploading a File (Or Files) With ASP.NET MVC
Я хотел убедиться в том как осуществляется загрузка файла или набора файлов с помощью ASP.NET MVC и первым результатом поиска по фразе “uploading a file with asp.net mvc” была статья в блоге Скотта Хансельмана.
Его статья очень подробна и помогает понять что происходит под капотом. У меня есть только одна претензия к коду, он может стать проще, потому что с тех пор мы доработали ASP.NET MVC 2. Я пишу эту статью в блог в надежде скинуть его статью с первого места.

Загрузка одиночного файла

Давайте начнем с создания представления. Вот форма, которая будет возвращать результат в текущий метод контроллера.

<form action="" method="post" enctype="multipart/form-data">
  
  <label for="file">Filename:</label>
  <input type="file" name="file" id="file" />

  <input type="submit" />
</form>

Вот метод контроллера, в который будет возвращаться результат из представления и сохраняться в директорию “uploads” на сервере.

[HttpPost]
public ActionResult Index(HttpPostedFileBase file) {
            
  if (file.ContentLength > 0) {
    var fileName = Path.GetFileName(file.FileName);
    var path = Path.Combine(Server.MapPath("~/uploads"), fileName);
    file.SaveAs(path);
  }
            
  return RedirectToAction("Index");
}

Обратите внимание, аргумент метода является экземпляром типа HttpPostedFileBase. ASP.NET MVC 2 представляет новую возможность — провайдеры значений (value providers), о которых я уже писал ранее.

“В то время как model binders используются для связывания входных данных с объектной моделью, провайдеры значений представляют абстракцию для самих входных данных.”

В данном случае провайдер значений по умолчанию называется HttpFileCollectionValueProvider, который предоставляет загруженные файлы в model binder. Также обратите внимание на имя аргумента — file, оно совпадает с именем переданного файла. Это очень важно что бы model binder загруженного файла совпадал с аргументом метода контроллера.

Загрузка нескольких файлов

В данном сценарии мы хотим загрузить набор файлов. Мы просто можем иметь несколько полей с одинаковыми именами для выбора файла.

<form action="" method="post" enctype="multipart/form-data">
    
  <label for="file1">Filename:</label>
  <input type="file" name="files" id="file1" />
  
  <label for="file2">Filename:</label>
  <input type="file" name="files" id="file2" />

  <input type="submit"  />
</form>

Теперь мы можем просто подкрутить наш метод контроллера, что бы принимать аргументы типа IEnumerable. Снова обратите внмание, что имя аргумента должно совпадать с именем передаваемого из формы поля.

[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> files) {
  foreach (var file in files) {
    if (file.ContentLength > 0) {
      var fileName = Path.GetFileName(file.FileName);
      var path = Path.Combine(Server.MapPath("~/uploads"), fileName);
      file.SaveAs(path);
    }
  }
  return RedirectToAction("Index");
}

Да, это очень просто. :)

  • roman

    Не работает с файлами большого размера

  • http://twitter.com/AlexandrYZ Alexandr Zaozersky

    roman, какой размер файлов, и суммарный размер?

  • roman

    > 50 M уже не работает. IE пишет что потеряна связь с сервером. Маленькие файлы работают отлично. Проверяю в отладочном режиме запуская из-под студии

  • http://twitter.com/AlexandrYZ Alexandr Zaozersky

    Понятно, есть одна догадка о причине, которую нужно проверить. Результат опубликую отдельным постом.

  • roman

    Буду премного благодарен если скините ссылочку на этот пост сюда или мне на почту
    zolroman@gmail.com