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:

  • ViewResult : Responsável por exibir uma View.
  • ContentResult : Retorna apenas texto.
  • FileResult : A saída é o conteúdo de um arquivo.
  • JavaScriptResult : A saída para o conteúdo de um arquivo JavaScript.
  • JSonResult : Retorna as anotações do Json.

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.

img
Figura 1. Criação do projeto no visual studio 2012
img
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("{0} 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.

img
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.

img
Figura 4. Estrutura da View Upload
img
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.

img
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.

img
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.

img
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.

img
Figura 9. View download listando os arquivos

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

img
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.