16 сентября 2012 г.

Загрузка файлов на сервер, используя Kendo UI Upload в ASP.Net MVC. Часть 1

Продолжая знакомство с бесплатными компонентами Kendo UI, сегодня мы будем пробовать внедрять в проект новый загрузчик файлов. В этом посте, мы рассмотрим только работу с обычной, синхронной загрузкой файлов на сервер. Тоесть с формой, submit-ом, и прочими мелочами.

Мы опробуем Kendo UI Upload в трех ситуациях:
  1. Простая загрузка файла на сервер;
  2. Загрузка файла с дополнительными параметрами, отработка события загрузчика "OnSelect";
  3. Пакетная загрузка файлов (мультизагрузка), отработка события "OnRemove"
Для подготовки к нашим примерам, давайте создадим в корне проекта папку для загрузок "Uploads", а в web.config (в разделе appSettings) пропишем параметр - путь к этой папке, чтобы удобнее обращаться к ней из кода:

  <appSettings>
    ...............
    
    <add key="Storage" value="~/Uploads/" />
  </appSettings>

Простая загрузка файла на сервер

Разместим в представлении простую форму:

   1:  <form method="post" style="width: 45%">
   2:  <div>
   3:      <input name="fileInput" id="fileInput" type="file" />
   4:      <p>
   5:          <input type="submit" value="Submit" class="k-button" />
   6:      </p>
   7:  </div>
   8:  </form>

Здесь у нас лишь поле для выбора файла, и кнопка отправки формы.
Теперь привяжем компонент Kendo Upload к элементу inputFile:

   1:  <script type="text/javascript">
   2:      $(function () {
   3:          $("#inputFile").kendoUpload({
   4:              multiple: false
   5:          });
   6:      });
   7:  </script>

Мы задали единственный параметр загрузчика - загрузка только одного файла.

На клиенте больше ничего не потребуется. Теперь нужно написать Action, который будет обрабатывать отправку формы:

   1:  [HttpPost]
   2:  public ActionResult Index(HttpPostedFileBase inputFile)
   3:  {
   4:      if (inputFile != null)
   5:      {
   6:          string virtualPath = ConfigurationManager.AppSettings["Storage"] +           inputFile.FileName;
   7:          string physicalPath = Server.MapPath(virtualPath);
   8:          if (System.IO.File.Exists(physicalPath))
   9:              System.IO.File.Delete(physicalPath);
  10:          inputFile.SaveAs(physicalPath);
  11:   
  12:          return RedirectToAction("Uploaded");
  13:      }
  14:   
  15:      return View();
  16:  }

Наш POST-Action должен принимать параметр типа HttpPostedFileBase, это и будет отправленный формой файл. Стоит заметить, что имя входящего параметра должно соответствовать имени Kendo-загрузчика.
Коротко пройдемся по методу...
Вначале проверяем, принят ли какой-либо файл. Если нет, то возвращаем пользователя на страницу загрузки. Иначе, формируем путь для нового файла и сохраняем его на сервере, предварительно удалив дубликат, если такой имеется. А в конце метода, если все прошло успешно, направляем пользователя на страницу информации о успешной загрузки.

Загрузка файла с дополнительными параметрами, отработка события загрузчика "OnSelect"

Давайте попробуем вместе с файлом отправить на сервер какой-то дополнительный параметр. Например - новое имя для файла.
Сценарий будет следующий - пользователь выбрал файл для загрузки - на форме появляется дополнительное поле, в которое можно ввести новое имя для этого файла на сервере.

Начнем с формы:

   1:  <form method="post" style="width: 45%">
   2:  <div>
   3:      
   4:      <input name="inputFile" id="inputFile" type="file" />
   5:      <br />
   6:      <div id="filenameDiv" style="display: none;">
   7:          New file name:<input name="f_name" id="f_name" 
            type="text" class="k-textbox"
   8:              value="" />
   9:      </div>
  10:      <p>
  11:          <input type="submit" value="Submit" class="k-button" />
  12:      </p>
  13:  </div>
  14:  </form>

Здесь все как в первом примере формы, только имеется еще скрытый div filenameDiv, который содержит поле для нового имени. По-умолчанию этот div скрыт. Показывать мы его будем по наступлению события загрузчика "OnSelect", тоесть после выбора файла для загрузки:

   1:  <script type="text/javascript">
   2:      $(function () {
   3:          $("#inputFile").kendoUpload({
   4:              multiple: false,
   5:              select: function (e) {
   6:                  $('#filenameDiv').show();
   7:              }
   8:          });
   9:      });
  10:  </script>

Ну и, конечно же, сама обработка отправки формы:

   1:  [HttpPost]
   2:  public ActionResult SyncMeta(HttpPostedFileBase inputFile, string f_name)
   3:  {
   4:      if (inputFile != null)
   5:      {
   6:          string newName = string.Empty;
   7:          if (!string.IsNullOrEmpty(f_name))
   8:          {
   9:              int idx = inputFile.FileName.LastIndexOf(".");
  10:              string ext = inputFile.FileName.Substring(idx, 
                                 inputFile.FileName.Length - idx);
  11:              newName = f_name + ext;
  12:          }
  13:          else
  14:              newName = inputFile.FileName;
  15:   
  16:   
  17:          string virtualPath = ConfigurationManager.AppSettings["Storage"] +                                  newName;
  18:          string physicalPath = Server.MapPath(virtualPath);
  19:          if (System.IO.File.Exists(physicalPath))
  20:              System.IO.File.Delete(physicalPath);
  21:          inputFile.SaveAs(physicalPath);
  22:   
  23:          return RedirectToAction("Uploaded");
  24:      }
  25:   
  26:      return View();
  27:  }

В этом методе мы проверяем было ли передано новое имя. Если такое имеется, то сначала мы определяем расширение принятого файла, затем прибавляем его к новому имени. Если же новое имя не пришло, то сохраняем файл под тем же именем, с которым он был отправлен. Далее следует уже стандартное сохранение файла на сервер.

Вот, как примерно должна выглядеть форма после выбора файла:

Пакетная загрузка файлов (мультизагрузка), отработка события "OnRemove"

Последним примером будет загрузка на сервер сразу нескольких файлов.
Форма загрузки имеет простой, стандартный вид. Единственное отличие - мы разместили в ней span, который будет выступать в роли консоли, где будут отображаться действия с загрузчиком:

   1:  <form method="post" style="width: 45%">
   2:  <div>
   3:      <input name="files" id="files" type="file" />
   4:      <br />
   5:      <span id="consoleSpan"></span>
   6:      <p>
   7:          <input type="submit" value="Submit" class="k-button" />
   8:      </p>
   9:  </div>
  10:  </form>

Все выбранные для загрузки файлы формируют некую очередь. Этой очередью можно управлять из Javascript-кода, получать доступ к ее элементам и прочее. Мы же будем обрабатывать событие "OnRemove". Оно срабатывает когда какой-то файл удаляется из очереди. Вот наш javascript-код:

   1:  <script type="text/javascript">
   2:      $(function () {
   3:          $("#files").kendoUpload({
   4:              remove: onRemove
   5:          });
   6:      });
   7:   
   8:      function onRemove(e) {
   9:          var files = e.files;
  10:   
  11:          var console = $('#consoleSpan');
  12:   
  13:          $.each(e.files, function (index, value) {
  14:              console.append('Removed file info -------- ');
  15:              console.append('Name: ' + value.name + '; ');
  16:              console.append('Size: ' + value.size + ' bytes; ');
  17:              console.append('Extension: ' + value.extension + ';</br>');
  18:          });
  19:   
  20:      };
  21:  </script>

При каждом удалении файла из очереди, мы будем выводить в нашу "консоль" информацию о удаленном файле. А именно: имя файла, его размер и расширение.

Теперь давайте посмотри на POST-Action обработки:

   1:  [HttpPost]
   2:  public ActionResult SyncMulti(HttpPostedFileBase[] files)
   3:  {
   4:      if (files != null)
   5:      {
   6:          foreach (var f in files)
   7:          {
   8:              string virtualPath = ConfigurationManager.AppSettings["Storage"] + f.FileName;
   9:              string physicalPath = Server.MapPath(virtualPath);
  10:              if (System.IO.File.Exists(physicalPath))
  11:                  System.IO.File.Delete(physicalPath);
  12:              f.SaveAs(physicalPath);
  13:          }
  14:   
  15:          return RedirectToAction("Uploaded");
  16:      }
  17:   
  18:      return View();
  19:  }

Здесь нет ничего особенного. Action принимает не единственный объект типа HttpPostedFileBase, а массив таких объектов т.к. их может быть много. А далее, в цикле, все файлы сохраняются по указанному месту на сервере.

Вот как должна выглядеть форма при удалении файлов из очереди загрузки:


На этом все. Думаю, что с синхронной загрузкой файлов все понятно.
Это была первая часть знакомства с компонентом Upload. В следующем посте мы будем испытывать разные варианты и сценарии асинхронной загрузки файлов на сервер. используя Kendo Upload. Будет еще интереснее!

Вторая часть статьи

P.S. Помните, что локальный веб-сервер (встроенный или IIS) ставит ограничение на размер загружаемого файла. Поэтому не нужно забывать указать необходимый макс. размер передаваемого контента в web.config, иначе ничего не будет загружаться.

_____
Исходники