ASP .NET MVC -  Enviando múltiplos arquivos para o servidor (C#)


 Neste artigo vou mostrar como enviar múltiplos arquivos para o servidor em  uma aplicação ASP .NET MVC usando a linguagem C#.

Enviar arquivos para o servidor é uma tarefa rotineira e simples, e, existem muitos componentes que realizam esta tarefa.

Durante o processo de envio de arquivos ou upload, somente duas partes do modelo MVC interagem :  a view e o controller. Vamos examinar o processo passo a passo:

  1. Um usuário visita  uma página web e para enviar arquivos (a página aqui é representada pela view);
  2. Quando o upload é iniciado,  o componente que envia os arquivos empacota os arquivos em uma requisição POST e a envia para o servidor;
  3. A ASP.NET põe no cache todos os dados na memória do servidor ou no disco dependendo do tamanho dos arquivos enviados;
  4. A ASP.NET MVC define o controlador e o método Action apropriado que irá tratar a requisição;
  5. O método Action trata a requisição (salva no disco, no banco de dados, etc., através da propriedade Controller.Request  a qual obtém o objeto HttpPostedFilesBase para a requisição atual;
  6. A ASP.NET MVC envia uma resposta para o cliente através de Controller.Response;

Nota: A classe HttpPostedFilesBase serve como o classe base para classes que fornecem acesso a arquivos individuais que foram carregados por um cliente.

Podemos configurar as opções de upload definindo atributos no arquivo web.config se você desejar realizar alterações no servidor. Vejamos alguns destes atributos:

  1. maxRequestLength - o limite do tamanho do request em Kilobytes ( o valor padrão é 4096 KB)
  2. requestLengthDiskThreshold - o limite dos dados armazenados no buffer na memória do servidor em kilobyte ( o padrão é 80 KB)
  3. executionTimeout - o tempo de execução permitida para a requisição antes do seu encerramento ( o padrão é 110 segundos)

Todos esses atributos devem ser definidos na seção <httpRunttime>.

Vamos criar uma aplicação ASP .NET MVC para enviar múltiplos arquivos para o servidor.

Recursos usados

Criando o projeto no VS Community

Abra o VS Community 2015  e clique em New Project;

A seguir selecione Visual C# -> Web -> ASP .NET Web Application;

Informe o nome Enviando_Arquivos_Mvc e clique no botão OK;

Selecione o template Empty e marque a opção MVC, sem autenticação, conforme figura a seguir:

Será criada uma solução com estrutura exibida abaixo:

Vamos criar em nosso projeto a pasta Imagens onde iremos salvar os arquivos enviados.

Selecione o projeto e no menu Project clique New Folder e informe o nome Imagens;

Definindo o modelo de dados na pasta Models

Vamos criar uma classe chamada Remessa na pasta models e definir nesta classe a propriedade Arquivos do tipo HttpPostedFilesBase  conforme o código a seguir:

using System.Collections.Generic;
using System.Web;
namespace Enviando_Arquivos_Mvc.Models
{
    public class Remessa
    {
        public IEnumerable<HttpPostedFileBase> Arquivos { get; set; }
    }
}

A propriedade Arquivos representa uma coleção de arquivos e é o nosso modelo de domínio.

Criando o controlador HomeController

Clique com o botão direito do mouse sobre a pasta Controllers;

A seguir clique em Add -> Controller e selecione MVC5 Controller Empty e clique no botão Add;

Informe o nome HomeController e clique no botão Add;

O controlador será criado com o método Action Index() que irá tratar a requisição GET. Precisamos definir o método Index() que vai tratar o POST quando os arquivos forem enviados.

Inclua o código para o método Action Index() que vai tratar o POST no controller conforme mostrado a seguir:

using System;
using System.Web.Mvc;
using Enviando_Arquivos_Mvc.Models;
using System.IO;
namespace Enviando_Arquivos_Mvc.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Index(Remessa arq)
        {
            try
            {
                string nomeArquivo = "";
                string arquivoEnviados = "";
                foreach (var arquivo in arq.Arquivos)
                {
                    if (arquivo.ContentLength > 0)
                    {
                        nomeArquivo = Path.GetFileName(arquivo.FileName);
                        var caminho = Path.Combine(Server.MapPath("~/Imagens"), nomeArquivo);
                        arquivo.SaveAs(caminho);
                    }
                    arquivoEnviados = arquivoEnviados + " , " + nomeArquivo;
                }
                ViewBag.Mensagem = "Arquivos enviados  : " + arquivoEnviados + " , com sucesso.";
            }
            catch (Exception ex)
            {
                ViewBag.Mensagem = "Erro : " + ex.Message;
            }
            return View();
        }
    }
}

O código acima utiliza um laço foreach para percorrer os arquivo selecionados, salvando-os na pasta Imagens.

Criando a View Index

Clique com o botão direito do mouse sobre o método Action Index e a seguir em Add View;

Aceite o nome Index e selecione o template : Empty, e clique no botão Add.

Será criado o arquivo Index.cshtml no interior da pasta /Views/Home.

Como marcamos a opção - Use a layout page - será instalado e referenciado o BootStrap na página _Layout.cshtml dentro da pasta /Views/Shared.

A seguir inclua o código abaixo no arquivo Index.cshtml:

@model Enviando_Arquivos_Mvc.Models.Remessa
@{
    ViewBag.Title = "Index";
}
<h2>Upload de Arquivos</h2>
@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="well">
        <table class="table table-striped">
            <tr>
                <td>Arquivo : </td>
                <td><input type="file" id="Arquivos" name="Arquivos" multiple /></td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><input type="submit" name="submit" value="Enviar Arquivo" /></td>
            </tr>
            <tr>
                <td>@ViewBag.Mensagem</td>
            </tr>
        </table>
    </div>
}

No formulário temos o método action acionando a Action Index do controlador Home (/Home/Index);

O método auxiliar é o método Html.BeginForm, que gera um elemento de formulário HTML configurado para um postback para o método action. 
Uma vez que não se passaram os parâmetros para o método auxiliar, ele assume que queremos dar um postback para a mesma URL. 
Um truque é usar isso em uma declaração using :
@using (Html.BeginForm()) {
   ...conteúdo do formulario...
   }
Normalmente a instrução using garante que um objeto é descartado quando sai do escopo. Ele é usado para conexões de bancos de dados, 
por exemplo, para se certificar de que elas serão fechadas assim que uma consulta for concluída.
Em vez de descartar um objeto, o Helper Html.BeginForm fecha o elemento de formulário HTML quando sai do escopo. Isto significa que o 
método Html.BeginForm cria ambas as partes de um elemento de formulário :
<form action="/Home/RsvpForm" method="post">
...conteudo do formulario...
</form>

Usamos o atributo enctype que especifica como os dados do formulário devem ser codificados quando enviá-lo para o servidor. (Ele só pode ser usado com o método POST).

O valor "multipart/form-data" indica que nenhum caractere é codificado. Esse valor é necessário quando você estiver usando formulários que têm um controle para upload de arquivo.

A tag <input type="file".../>  cria um objeto de upload de arquivo com uma caixa de texto e o botão procurar.

Também usamos alguns recursos do BootStrap definindo a classe  <div class="well"> e a tabela :  <table class="table table-striped">

No arquivo RouteConfig.cs da pasta App_Start, já defina a rota padrão usando o controlador Home. Assim, ao executar o projeto a Action Index do controlador HomeController será executada por padrão.

Agora é só alegria...

Executando (no IE Explorer) o projeto e realizando alguns uploads teremos o seguinte resultado:

1- Apresentação da view Index (GET) para o usuário selecionar os arquivos:

2 - Após selecionar alguns arquivos e clicar no botão Enviar Arquivo, ocorrerá o POST e obteremos a mensagem exibindo o nome dos arquivos enviados:

3 - Verificando o conteúdo da pasta Imagens vemos os arquivos salvos na pasta:

Este aplicativo é bem simples e permite que você transfira os arquivos do usuário para o servidor, mas ele não se importa com a segurança.  O servidor pode ser comprometido por vírus ou outros dados maliciosos enviados por alguém.

Assim, em uma aplicação mais robusta, você deve considerar adicionar algumas restrições de carregamento de arquivo no controlador, como por exemplo verificar a extensão do arquivo. Segue um exemplo abaixo que só permite arquivos com extensão .jpg e .png.

Dim arquivo As HttpPostedFileBase = Request.Files.[Get](0)
Dim extensaoPermitida = New String() {".jpeg", ".png"}
Dim extensao As String = Path.GetExtension(arquivo .FileName)


If extensaoPermitida .Contains(extensao ) Then
    // tratamento
Else
    // tratamento
End If

Nota: Se não quiser usar o compilador Roslyn desinstale via Nuget os pacotes :  (veja o artigo : ASP .NET - O compilador Roslyn (csc.exe  e vbc.exe ) e a hospedagem compartilhada )

Pegue o projeto aqui :   Enviando_Arquivos_Mvc.zip (sem as referências)

"Portanto nós também, pois que estamos rodeados de uma tão grande nuvem de testemunhas, deixemos todo o embaraço, e o pecado que tão de perto nos rodeia, e corramos com paciência a carreira que nos está proposta,"
Hebreus 12:1

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti