ASP.NET MVC 4: Realizando Upload e download de arquivos

Veja nesse artigo como funciona o desenvolvimento em camada através do desenvolvimento de uma aplicação que fará o download e o upload de imagens.

Neste artigo desenvolveremos uma aplicação em ASP.NET MVC 4 que será responsável por realizar o upload de imagens e também disponibilizá-las em seguida para download para o usuário, com o intuito principal de auxiliar desenvolvedores que estão em processo de migração para o MVC Framework. Neste artigo usaremos o Visual Studio 2012 e o plugin jQuery MultiFile.

Iniciaremos entendendo a filosofia de como o MVC trabalha com arquivos e diretórios: o ActionResult é a classe abstrata retornada por cada método das Actions. Várias classes herdam da ActionResult, inclusive a FileResult, que é responsável pelo envio de conteúdo do arquivo binário para o response. Vamos ver a seguir um pouco sobre essas classes:

Criando o Projeto

Vamos montar nosso ambiente criando uma aplicação ASP.NET MVC 4 Web Aplicattion usando o template InternetApllication e Razor como viewengine com o nome de MvcDownUpload no visual studio 2012, como mostrado nas Figuras 1 e 2.

Figura 1. Criação do projeto no visual studio 2012
Figura 2. Template InternetApplication com Razor

De início, nos preocuparemos em montar a estrutura da nossa aplicação. Para isso, criaremos uma classe Model que representará o arquivo com que a aplicação irá trabalhar. Nela irá conter as seguintes propriedades: Nome, Tamanho, Tipo e Caminho, como mostrado na Listagem 1.

public class UploadFileResult { public int IDArquivo { get; set; } public string Nome { get; set; } public int Tamanho{ get; set; } public string Tipo{ get; set; } public string Caminho { get; set; } }
Listagem 1. Código fonte do model

No próximo passo criaremos nossa classe Controller FileUpload que será responsável por realizar todo o trabalho de importação do arquivo, como mostrado na Listagem 2.

public class FileUploadController : Controller { // // GET: /FileUpload/ public ActionResult Index() { return View(); } public ActionResult FileUpload() { int arquivosSalvos = 0; for (int i = 0; i < Request.Files.Count; i++) { HttpPostedFileBase arquivo = Request.Files[i]; //Suas validações ...... //Salva o arquivo if (arquivo.ContentLength > 0) { var uploadPath = Server.MapPath("~/Content/Uploads"); string caminhoArquivo = Path.Combine(@uploadPath, Path.GetFileName(arquivo.FileName)); arquivo.SaveAs(caminhoArquivo); arquivosSalvos++; } } ViewData["Message"] = String.Format(" arquivo(s) salvo(s) com sucesso.", arquivosSalvos); return View("Upload"); } }
Listagem 2. Código fonte do Controller FileUpload

Agora precisaremos adicionar o plugin jQuery MultiFile ao nosso projeto. Para isso, clicaremos com o botão direito na pasta scripts e em seguida add existing item. Em seguida, localize onde foram salvos seus arquivos do plugin e clique em Add para todos, como mostrado na Figura 3.

Figura 3. Adicionando as referencias ao jQuery MultiFile
Nota: Para realizarem o download do plugin basta clicarem no link: FYNEWORKS

Por último, criaremos nossa camada de interface, adicionando de início duas Views chamadas index e upload, como mostrado nas Figuras 4 e 5.

Figura 4. Estrutura da View Upload
Figura 5. Estrutura da View index

Como vocês puderam notar, a estrutura das views de início é bem simples, formada por tags básicas do HTML, mas para fazermos nosso componente de upload funcionar devemos implementar uma função JavaScript e adicionarmos as referências aos arquivos .Js do plugin na tag Head da view Upload, como na Listagem 3.

<link href="~/Content/bootstrap/bootstrap.min.css" rel="stylesheet" /> <link href="~/Content/bootstrap/bootstrap-theme.min.css" rel="stylesheet" /> <script src="~/Scripts/jquery-1.9.1.min.js"></script> <script src="~/Scripts/jquery.ui.widget.js"></script> <script src="~/Scripts/bootstrap.min.js"></script> <script src="~/Scripts/jquery.MultiFile.js"></script> <script src="../../Scripts/jquery-1.3.2.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready(function () { $('#file').MultiFile({ accept: 'gif|jpg', max: 3, STRING: { remove: 'Remover', denied: 'Tipo do arquivo inválido $ext!', duplicate: 'Esse arquivo já foi selecionado:\n$file!' } }); }); </script>
Listagem 3. Função JavaScript responsável pelo Upload

Executaremos nossa aplicação para verificarmos como está o funcionamento desse primeiro fluxo, conforme mostrado na Figura 6.

Figura 6. Selecionando arquivo na View Upload

Na view Upload escolheremos o arquivo local que desejamos mandar e clicaremos no botão enviar, a aplicação executará nossa Action FileUpload criada anteriormente e realizará a importação do arquivo como mostrado na Figura 7.

Figura 7. Importação realizada com sucesso

Para comprovarmos que o arquivo foi importado, basta irmos à pasta onde escolhemos que nossos arquivos seriam salvos, que no caso é Content/Uploads, e verificarmos a existência dos mesmos, como mostrado na Figura 8.

Figura 8. Arquivos importados na pasta do projeto

Na segunda parte trataremos de desenvolver a lógica que listará nossos arquivos e os disponibilizará para download, onde primeiramente criaremos no nosso model UploadResult um método responsável por “pegar” os arquivos disponíveis, como mostrado na Listagem 4.

public List<UploadFileResult> ListaArquivos() { List<UploadFileResult> lstArquivos = new List<UploadFileResult>(); DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath("~/Content/Uploads")); int i = 0; foreach (var item in dirInfo.GetFiles()) { lstArquivos.Add(new UploadFileResult() { IDArquivo = i + 1, Nome = item.Name, Caminho = dirInfo.FullName + @"\" + item.Name }); i = i + 1; } return lstArquivos;
Listagem 4. Método de Listagem dos arquivos

Em seguida, definiremos o nosso Controller responsável pelos downloads, como mostrado na Listagem 5.

public class DownloadController : Controller { UploadFileResult oModelArquivos = new UploadFileResult(); public ActionResult Index() { var _arquivos = oModelArquivos.ListaArquivos(); return View(_arquivos); } public FileResult Download(string id) { int _arquivoId = Convert.ToInt32(id); var arquivos = oModelArquivos.ListaArquivos(); string nomeArquivo = (from arquivo in arquivos where arquivo.IDArquivo == _arquivoId select arquivo.Caminho).First(); string contentType = "application/pdf"; return File(nomeArquivo, contentType, "Report.pdf"); } }
Listagem 5. Fonte do Controller de Download

Na Listagem 6 criaremos nossa view de interface com o usuário.

@model IList<MvcDownUpload.Models.UploadFileResult> @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Importar Novo", "Upload") </p> <table> <tr> <th> Codigo </th> <th> Nome </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.IDArquivo) </td> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.ActionLink("Download", "Download", new { id = item.IDArquivo }) </td> </tr> } </table>
Listagem 6. Fonte da View Index do Controller de Downloads

Note que criamos essa view do tipo do nosso model UploadFileResult para que assim pudéssemos ter acesso a suas propriedades e, a partir dele, executaremos nossa Action Download que disponibilizará o arquivo para o cliente. Para testarmos vamos executar nossa aplicação mais uma vez, como mostrado na Figura 9.

Figura 9. View download listando os arquivos

Ao clicarmos em um arquivo será disponibilizada a janela de download, como mostrado na Figura 10.

Figura 10. Janela de Download do arquivo escolhido

Para finalizarmos vamos dar uma melhorada na nossa aplicação tirando a amarração feita no código fonte para que o download seja gerado apenas em formato .pdf. Para isso, realizaremos uma pequena alteração na nossa Action de download, como mostra a Listagem 7.

public FileResult Download(string id) { int _arquivoId = Convert.ToInt32(id); string contentType=""; var arquivos = oModelArquivos.ListaArquivos(Server.MapPath("~/Content/Uploads")); string nomeArquivo = (from arquivo in arquivos where arquivo.IDArquivo == _arquivoId select arquivo.Caminho).First(); string extensao = Path.GetExtension(nomeArquivo); string nomeArquivoV = Path.GetFileNameWithoutExtension(nomeArquivo); if (extensao.Equals(".pdf")) contentType = "application/pdf"; if (extensao.Equals(".JPG") || extensao.Equals(".GIF") || extensao.Equals(".PNG")) contentType = "application/image"; return File(nomeArquivo, contentType, nomeArquivoV+extensao); }
Listagem 7. Fonte do Controller de Downloads Alterado

Fazendo isso assim que recuperarmos nosso arquivo escolhido para download pelo id, poderemos recuperar sua extensão e atribuirmos o contentType adequado.

Artigos relacionados