ASP .NET Core  - Criando uma Galeria de Fotos


  Neste tutorial veremos como criar uma galeria de imagens usando a ASP .NET Core.

Este é um tutorial do tipo fazendo e aprendendo e nele vamos criar uma galeria de fotos usando a ASP .NET Core 5.0.

Para criar uma galeria de fotos, primeiro construímos um banco de dados para armazenar as fotos da galeria. Para aplicar um estilo nas imagens vamos usar a biblioteca Ekko-lightbox CSS e js.

Criando o projeto MVC

Abra o VS 2019 e selecione a opção New Project e selecione o template ASP .NET Core Web App     e informe o nome GaleriaFotos usando as seguintes configurações:

Vamos incluir os seguintes pacotes no projeto:

  1. Microsoft.EntityFrameworkCore.SqlServer
  2. Microsoft.EntityFrameworkCore.Tools

A seguir na pasta Models do projeto crie a classe Foto com o código abaixo:

    public class Foto
    {
        [Key]
        public int Id { get; set; }
        [StringLength(100)]
        public string Titulo { get; set; }
        [StringLength(100)]
        public string Nome { get; set; }
        [StringLength(255)]
        public string Caminho { get; set; }
        public int? Visualizacoes { get; set; }
    }

Nesta pasta Models crie a classe AppDbContext que deve herdar de DbContext e onde vamos definir o mapeamento da entidade Foto para a tabela Fotos:

using Microsoft.EntityFrameworkCore;

namespace GaleriaFotos.Models
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options)
            : base(options)
        {

        }
        public virtual DbSet<Foto> Fotos { get; set; }
    }
}

A seguir no arquivo appsettings.json vamos definir uma seção onde vamos definir a string de conexão com o banco de dados SQLite :

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=*****\\sqlexpress;Initial Catalog=GaleriaDB;Integrated Security=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Após isso abra o arquivo Startup e no método ConfigureServices inclua o serviço para o contexto do SQL Server usando a string de conexão definida acima:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

     services.AddControllersWithViews();
}

Agora podemos aplicar o migrations do EF Core.

Vamos usar esta ferramenta na janela Package Manager Console do Visual Studio 2019.

Abra a janela e digite o seguinte comando: add-migration Inicial

Este código irá criar um script de migração que poderá ser aplicado usando o comando: update-database

Com isso teremos o banco de dados GaleriaDB criado e pronto para ser usado.

Criando a ViewModel e o Controller

Vamos agora criar no projeto a pasta ViewModels e nesta pasta a classe FotoViewModel :         

using GaleriaFotos.Models;
using System.Collections.Generic;

namespace GaleriaFotos.ViewModels
{
    public class FotoViewModel
    {
        public Foto fotografia { get; set; }
        public List<Foto> listaFotos { get; set; }
    }
}

Vamos usar esta view model para exibir a lista de fotos na view e para isso vamos alterar o nosso model.

A propriedade fotografia é do tipo Foto e a propriedade listaFotos é uma lista de objetos Foto para exibição.

Para obter várias fotos de um único ViewModel, na tabela Fotos, vamos incluir uma propriedade adicional chamada arquivoFoto, do tipo List<IFormFile> na classe Foto, que não iremos mapear para o banco de dados. Portanto, vamos decorá-lo com o atributo [NotMappedAttribute]. Esta propriedade nos ajudará a obter uma lista de fotos do usuário.

    public class Foto
    {
        [Key]
        public int Id { get; set; }
        [StringLength(100)]
        public string Titulo { get; set; }
        [StringLength(100)]
        public string Nome { get; set; }
        [StringLength(255)]
        public string Caminho { get; set; }
        public int? Visualizacoes { get; set; }

         [NotMappedAttribute]
         [Required(ErrorMessage = "Foto é requerida.")]
         public List<IFormFile> arquivoFoto { get; set; }

    }

E agora podemos criar na pasta Controllers o controlador GaleriaController com o código abaixo:

using GaleriaFotos.Models;
using GaleriaFotos.ViewModels;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;

namespace GaleriaFotos.Controllers
{
    public class GaleriaController : Controller
    {
        private readonly AppDbContext _db;
        public GaleriaController(AppDbContext db)
        {
            _db = db;
        }

        public IActionResult Index()
        {
            FotoViewModel viewModel = new FotoViewModel();
            viewModel.listaFotos = _db.Fotos.ToList();
            viewModel.fotografia = new Foto();
            return View(viewModel);
        }    

        [HttpPost]
        public IActionResult IncluiFotos(FotoViewModel model)

        {
            if (!ModelState.IsValid)
                return View(model);

            var Files = model.fotografia.arquivoFoto;

            if (Files.Count > 0)
            {
                foreach (var item in Files)
                {
                    Foto fotografia = new Foto();
                    var guid = Guid.NewGuid().ToString();
                    var filePath = "wwwroot/fotografias/" + guid + item.FileName;
                    var fileName = guid + item.FileName;
                    using (var stream = System.IO.File.Create(filePath))
                    {
                        item.CopyTo(stream);
                        fotografia.Nome = fileName;
                        fotografia.Caminho = filePath;
                        fotografia.Titulo = item.FileName;
                        fotografia.Visualizacoes = 1;
                        _db.Fotos.Add(fotografia);
                        _db.SaveChanges();
                    }
                }
                return RedirectToAction("Index");
            }
            return RedirectToAction("Index");
        }

        public IActionResult DeletaFoto(int id)
        {
            var photo = _db.Fotos.Find(id);
            if (photo != null)
            {
                _db.Fotos.Remove(photo);
                _db.SaveChanges();
            }
            return RedirectToAction("index");
        }
   }
}

No código estamos injetando uma instância do contexto no construtor do controlador e no método Action Index estamos obtendo uma lista de fotos para exibir na view Index.

Definimos também  os métodos Action para deletar e incluir fotos.  Para poder armazenar fisicamente as fotos vamos criar uma pasta fotografias dentro da pasta wwwroot.

Instalando a biblioteca Ekko-lightbox e definindo o layout

Agora antes de criar a view Index vamos incluir a biblioteca Ekko-lightbox no projeto. Para isso clique com o botão direito sobre a pasta wwwroot e selecione Add->Client-Side Library e a seguir informe o nome ekko-lightbox@5.30 :

Defina as opções conforme mostrado na imagem acima e clique em Install.

Agora abra o arquivo _Layout.cshml na pasta /Views/Shared e inclua as bibliotecas css e js da biblioteca ekko-lightbox no arquivo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - GaleriaFotos</title>

    <link href="~/ekko-lightbox/ekko-lightbox.css" rel="stylesheet" />

    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
...
 <ul class="navbar-nav flex-grow-1">
   <li class="nav-item">
     <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-controller="Galeria" asp-action="Index">Fotos</a>
   </li>
</ul>

...
 </footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>

<script src="~/ekko-lightbox/ekko-lightbox.min.js"></script>

<script src="~/js/site.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Aproveitamos a incluímos também uma opção de menu para poder acessar o método Action Index do controlador Galeria.

Criando a view Index

Agora vamos criar a view Index para exibir as fotos e também poder remover uma foto selecionada:

@model GaleriaFotos.ViewModels.FotoViewModel

@{
    ViewData["Title"] = "Index";
}

<div class="col-12">
    <div class="card card-primary">
        <div class="card-header">
            <div class="card-title">
               Galeria de Fotos
            </div>
        </div>
        <div class="card-body">

            <form id="frmPhototGraphy" class="form-horizontal" asp-action="IncluiFotos" asp-controller="galeria"
method="post" enctype="multipart/form-data">
                <div class="col-md-6 col-sm-6">

                    <div class="form-group row">
                        <label class="col-sm-2 col-form-label">Foto</label>

                        <div class="col-sm-6 custom-file">

                            <input asp-for="@Model.fotografia.arquivoFoto" type="file" class="custom-file-input" multiple="multiple">
                            <label class="custom-file-label" for="@Model.fotografia.arquivoFoto">Escolha a foto</label>
                            <span asp-validation-for="@Model.fotografia.arquivoFoto" class="text-danger"></span>

                        </div>
                        <div class="col-sm-4"> <button type="submit" class="btn btn-danger">Envia Fotos</button></div>
                    </div>
                </div>
            </form>
            <br />
            <div class="row">
                @if (Model.listaFotos != null)
                {
                    foreach (var item in Model.listaFotos)
                    {
                        <div class="col-sm-2">
                            <a href="@Url.Content("~/fotografias/"+item.Nome)" data-toggle="lightbox"
data-title="@item.Titulo" data-gallery="gallery">
                                <img src="~/fotografias/@item.Nome" asp-append-version="true" class="img-fluid mb-2" alt="foto">
                            </a>
                            <a href="@Url.Action("DeletaFoto","galeria",new { id=item.Id})" style="float:right">Deletar</a>
                        </div>
                    }
                }
            </div>
        </div>
    </div>
</div>

@section Scripts{
    <script>
            $(function () {
                $(document).on('click', '[data-toggle="lightbox"]', function (event) {
                    event.preventDefault();
                    $(this).ekkoLightbox({
                        alwaysShowClose: true
                    });
                });
            });
    </script>

}

Com isso temos a view e o código javascript usado para que quando o usuário clicar na imagem ela seja exibida no centro da página em um tamanho maior.

Executando o projeto teremos o seguinte resultado:

Pegue o código do projeto aqui:  GaleriaFotos.zip (sem as referências)

"Porém, respondendo Pedro e os apóstolos, disseram: Mais importa obedecer a Deus do que aos homens."
Atos 5:29

Referências:


José Carlos Macoratti