ASP .NET Core 5 - CRUD com EF Core 5 usando imagens - II


Hoje vamos iniciar a criação de um projeto web usando a ASP .NET Core 5.0 onde vamos realizar um CRUD com a ajuda do EF Core 5.0 e também mostrar como tratar imagens.

Continuando a primeira parte do artigo vamos definir as view models para customizar a exibição dos dados em nosso projeto.

Criando as ViewModels

Vamos criar uma pasta chamada ViewModels no projeto e a seguir vamos criar as seguintes classes nesta pasta:

1-  UploadImagemViewModel

using Microsoft.AspNetCore.Http;
using System.ComponentModel.DataAnnotations;
namespace Palestras.ViewModels
{
    public class UploadImagemViewModel
    {
        [Required]
        [Display(Name = "Foto")]
        public IFormFile PalestranteFoto { get; set; }
    }
}

Aqui estamos usando a interface IFormFile que representa o arquivo enviado com o request. Vamos usar este recurso para fazer o upload da imagem do palestrante.

2- EditImagemViewModel

 public class EditImagemViewModel : UploadImagemViewModel
 {
        public int Id { get; set; }
        public string ImagemExistente { get; set; }
 }

Esta classe permite tratar as imagens já existentes que foram enviadas.

3- PalestranteViewModel

using System;
using System.ComponentModel.DataAnnotations;
namespace Palestras.ViewModels
{
    public class PalestranteViewModel : EditImagemViewModel
    {
        [Required]
        public string Nome { get; set; }
        [Required]
        [Display(Name = "Qualificação")]
        public string Qualificacao { get; set; }
        [Required]
        [Display(Name = "Experiência")]
        public int Experiencia { get; set; }
        [Required]
        [DataType(DataType.Date)]
        [Display(Name = "Data")]
        public DateTime DataPalestra { get; set; }
        [Required]
        [DataType(DataType.Time)]
        [Display(Name = "Hora")]
        public DateTime HoraPalestra { get; set; }
        [Required]
        public string Local { get; set; }
    }
}

Esta viewmodel temos as informações do palestrante que iremos usar para realizar a edição dos dados.

Criamos assim 3 ViewModels definindo as propriedades que iremos usar para gerenciar a exibição das informações do palestrante.

Ajustando o código do controlador PalestrantesController

Agora com base nas ViewModels criadas vamos ajustar o código que foi gerado pelo Scaffold no controlador PalestrantesController.

Vamos incluir no controlador uma instância da interface IWebHostEnvironment além da instância do contexto que foi incluida pelo Scaffold:

 public class PalestrantesController : Controller
 {
        private readonly AppDbContext _context;
        private readonly IWebHostEnvironment webHostEnvironment;

        public PalestrantesController(AppDbContext context, IWebHostEnvironment hostEnvironment)
        {
            _context = context;
            webHostEnvironment = hostEnvironment;
        }
    ...
  }

Após isso vamos criar o método ProcessaUploadedFile() que vai gerenciar o Upload dos arquivos salvando os arquivos enviados na pasta Uploads dentro da pasta wwwroot :

  private string ProcessaUploadedFile(PalestranteViewModel model)
  {
            string nomeArquivoImagem = null;
            if (model.PalestranteFoto != null)
            {
                string uploadsFolder = Path.Combine(webHostEnvironment.WebRootPath, "Uploads");
                nomeArquivoImagem = Guid.NewGuid().ToString() + "_" + model.PalestranteFoto.FileName;
                string filePath = Path.Combine(uploadsFolder, nomeArquivoImagem);
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    model.PalestranteFoto.CopyTo(fileStream);
                }
            }
            return nomeArquivoImagem;
   }

A seguir temos os métodos Action com a alteração pertinente para tratar a imagem do usuário e usar as view models criadas:

1- Método Details

        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var palestrante = await _context.Palestrantes
                .FirstOrDefaultAsync(m => m.Id == id);
            var palestranteViewModel = new PalestranteViewModel()
            {
                Id = palestrante.Id,
                Nome = palestrante.Nome,
                Qualificacao = palestrante.Qualificacao,
                Experiencia = palestrante.Experiencia,
                DataPalestra = palestrante.DataPalestra,
                HoraPalestra = palestrante.HoraPalestra,
                Local = palestrante.Local,
                ImagemExistente = palestrante.Foto
            };
            if (palestrante == null)
            {
                return NotFound();
            }
            return View(palestrante);
        }

2- Método Create (Post)

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create(PalestranteViewModel model)
        {
            if (ModelState.IsValid)
            {
                string nomeArquivoImagem = ProcessaUploadedFile(model);
                Palestrante palestrante = new Palestrante
                {
                    Nome = model.Nome,
                    Qualificacao = model.Qualificacao,
                    Experiencia = model.Experiencia,
                    DataPalestra = model.DataPalestra,
                    HoraPalestra = model.HoraPalestra,
                    Local = model.Local,
                    Foto = nomeArquivoImagem
                };
                _context.Add(palestrante);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(model);
        }

3- Método Edit (Get)

 public async Task<IActionResult> Edit(int? id)
 {
            if (id == null)
            {
                return NotFound();
            }
            var palestrante = await _context.Palestrantes.FindAsync(id);
            var palestranteViewModel = new PalestranteViewModel()
            {
                Id = palestrante.Id,
                Nome = palestrante.Nome,
                Qualificacao = palestrante.Qualificacao,
                Experiencia = palestrante.Experiencia,
                DataPalestra = palestrante.DataPalestra,
                HoraPalestra = palestrante.HoraPalestra,
                Local = palestrante.Local,
                ImagemExistente = palestrante.Foto
            };
            if (palestrante == null)
            {
                return NotFound();
            }
            return View(palestranteViewModel);
        }

4- Método Edit (Post)

         [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, PalestranteViewModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    var palestrante = await _context.Palestrantes.FindAsync(model.Id);
                    palestrante.Nome = model.Nome;
                    palestrante.Qualificacao = model.Qualificacao;
                    palestrante.Experiencia = model.Experiencia;
                    palestrante.DataPalestra = model.DataPalestra;
                    palestrante.HoraPalestra = model.HoraPalestra;
                    palestrante.Local = model.Local;
                    if (model.PalestranteFoto != null)
                    {
                        if (model.ImagemExistente != null)
                        {
                            string filePath = Path.Combine(webHostEnvironment.WebRootPath, "Uploads", model.ImagemExistente);
                            System.IO.File.Delete(filePath);
                        }
                        palestrante.Foto = ProcessaUploadedFile(model);
                    }
                    _context.Update(palestrante);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                   throw;
                }
                return RedirectToAction(nameof(Index));
            }
            return View();
        }

5- Método Delete

        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var palestrante = await _context.Palestrantes
                .FirstOrDefaultAsync(m => m.Id == id);
            var palestranteViewModel = new PalestranteViewModel()
            {
                Id = palestrante.Id,
                Nome = palestrante.Nome,
                Qualificacao = palestrante.Qualificacao,
                Experiencia = palestrante.Experiencia,
                DataPalestra = palestrante.DataPalestra,
                HoraPalestra = palestrante.HoraPalestra,
                Local = palestrante.Local,
                ImagemExistente = palestrante.Foto
            };
            if (palestrante == null)
            {
                return NotFound();
            }
            return View(palestranteViewModel);
        }

6- Método DeleteConfirmed

        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int? id)
        {
            var palestrante = await _context.Palestrantes.FindAsync(id);
            var CurrentImage = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\uploads", palestrante.Foto);

            _context.Palestrantes.Remove(palestrante);
            if (await _context.SaveChangesAsync() > 0)
            {
                if (System.IO.File.Exists(CurrentImage))
                {
                    System.IO.File.Delete(CurrentImage);
                }
            }
            return RedirectToAction(nameof(Index));
        }

Pronto agora já temos tudo pronto e teremos que fazer alguns ajustes nas views geradas na pasta /Views/Palestrantes que você pode ver no arquivo anexo contendo o projeto.

Executando o projeto teremos o resultado a seguir:

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

Referências:


José Carlos Macoratti