ASP .NET Core MVC - Salvando e Exibindo Imagens usando o SQL Server

 Neste artigo eu vou mostrar como salvar imagens e a seguir exibir as imagens salvar em um banco de dados SQL Server a partir de uma aplicação ASP .NET Core MVC.

Quando você precisa tratrar com dados binários como imagens, a maneira mais usada para armazenar esses dados binários é no sistema de arquivos do sistema operacional ou seja do Windows; assim você armazena os dados binários como um arquivo no disco local.

A outra abordagem é armazenar os dados binários diretamente em um banco de dados como o SQL Server que será o nosso caso.

Cada opção possui seus prós e seus contras, a seguir eu relaciono alguns motivos que podem justificar cada opção:

1 - Armazenar os dados binários como um arquivo no disco local é uma boa opção se :

O grande problema com esta solução que os dados estarão fora do banco de dados e podem perder a sincronia com os demais dados em operações de exclusão, atualização, inclusão e transferência de dados. Outro fator a considerar é que o backup deverá ser feito separado.

2 - Armazenar os dados binários diretamente no banco de dados SQL Server possui as seguinte vantagens:

Usando o tipo de dados varbinary  do SQL Server podemos armazenar arquivos com até 2GB de tamanho.

Para estes casos específicos o SQL Server fornece um tipo de dados especial apropriados para um grande volume de dados e neste artigo eu vou mostrar como podemos ler e gravar BLOBs - Binary Large Objects no SQL Server em uma aplicação ASP .NET Core MVC.

 Nota: BLOB é um acrônimo para binary large object , uma coleção de dados binários armazenados em um identidade única no SQL Server.

Estes tipos de dados, Large Objects , podem ser classificados em CLOBs - Character Large Objects ou BLOBs - Binary Large Objects e o SQL Server possui um tipo diferente de dados para cada um destes objetos. Vejamos na tabela abaixo os tipos de dados que podemos usar neste caso:

LOB Type Tipo de dados SQL  Server Tamanho Máximo Os tipos de dados (*) Text, NText e Image já existiam em versões anteriores do SQL Server. É recomendado que você use os novos tipos de dados : varchar(MAX), nvarchar(MAX) e  varbinary(MAX)

Observando a tabela vemos que o tipo de dados  varbinary(MAX) é o que permite tratar com imagens ou Large Binary Data.

BLOB varbinary(MAX) 
Image(*)
2.147.483.647
CLOB varchar(MAX)
Text(*)
2.147.483.647
CLOB - Unicode nvarchar(MAX)
NText(*)
1.073.741.823
dados XML xml 2.147.483.647

No exemplo deste artigo eu vou partir de um banco de dados existente no SQL server chamado Estudo e de uma tabela Imagens com a seguinte estrutura:

USE Estudo
GO

CREATE TABLE dbo.Imagens(
Id int IDENTITY(1,1) NOT NULL,
Nome nvarchar(150) NOT NULL,
ContentType nvarchar(50) NOT NULL,
Dados varbinary(max) NULL,

 CONSTRAINT [PK_Imagens] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

Ao lado vemos o script SQL para gerar a tabela. Note que o tipo de dados para a imagem (Dados) é varbinary(max).

Recursos usados:

Criando o projeto no VS 2017

Abra o VS 2017 Community e crie um novo projeto ASP .NET Core usando o template Web Application(Model-View-Controller).

  • Create New Project;
  • Visual C# -> Web -> ASP .NET Core Web Application;
  • Informe o nome AspCore_EnviaExibeImagem
  • Selecione o template Web Application(Model-View-Controller) , marque ASP .NET Core 2.0;

Após criar o projeto já podemos definir o modelo e o contexto usados na nossa aplicação.

Criando o modelo de domínio e o conexto

Vamos criar a classe Imagem que representa o nosso modelo de domínio na pasta Models:

public class Imagem
    {
        public int Id { get; set; }
        public string Nome { get; set; }
        public byte[] Dados { get; set; }
        public string ContentType { get; set; }
    }

 

A seguir vamos criar a classe de contexto ImagemDbContext que herda de DbContext na pasta Models :

using Microsoft.EntityFrameworkCore;
namespace AspNetCore_EnviaExibeImagem.Models
{
    public class ImagemDbContext : DbContext
    {
        public ImagemDbContext(DbContextOptions<ImagemDbContext> options) : base(options)
        { }
        public DbSet<Imagem> Imagens { get; set; }
    }
}

Definindo a string de conexão no arquivo appsettings.json

Precisamos informar ao Entity Framework qual o caminho do banco de dados que vamos acessar. Para isso vamos incluir a string de conexão no arquivo appsettings.json :

{
  "ConnectionStrings": {
    "ImagemContext": "Data Source=Macoratti;Initial Catalog=Estudo;Integrated Security=True"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Registrandao o contexto e configurando o serviço em Startup

Vamos registrar o nosso contexto no método ConfigureServices da classe Startup definindo também a utilização do provedor do SQL Server e obtendo a string de conexão definida no arquivo appsettings.json:

....
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ImagemDbContext>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("ImagemContext")));
            services.AddMvc();
        }
...

Agora já temos tudo pronto para acessar o banco de dados. Vamos criar nosso controlador.

Criando o controlador ImagensController e  view Index

Clique com o botão direito do mouse sobre a pasta Controllers e a seguir clique em Add -> Controller e escolha a opção MVC Controller Empty e clique Add;

Informe o nome ImagensController e a seguir defina o código abaixo neste controlador :

using AspNetCore_EnviaExibeImagem.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace AspNetCore_EnviaExibeImagem.Controllers
{
    public class ImagensController : Controller
    {
        ImagemDbContext _context;
        public ImagensController(ImagemDbContext contexto)
        {
            _context = contexto;
        }
        [HttpGet]
        public IActionResult Index()
        {
            List<int> imagens = _context.Imagens.Select(m => m.Id).ToList();
            return View(imagens);
        }
        [HttpPost]
        public IActionResult UploadImagem(IList<IFormFile> arquivos)
        {
            IFormFile imagemEnviada = arquivos.FirstOrDefault();
            if (imagemEnviada != null || imagemEnviada.ContentType.ToLower().StartsWith("image/"))
            {
                MemoryStream ms = new MemoryStream();
                imagemEnviada.OpenReadStream().CopyTo(ms);
                Imagem imagemEntity = new Imagem()
                {
                    Nome = imagemEnviada.Name,
                    Dados = ms.ToArray(),
                    ContentType = imagemEnviada.ContentType
                };
                _context.Imagens.Add(imagemEntity);
                _context.SaveChanges();
            }
            return RedirectToAction("Index");
        }
        [HttpGet]
        public FileStreamResult VerImagem(int id)
        {
            Imagem imagem = _context.Imagens.FirstOrDefault(m => m.Id == id);
            MemoryStream ms = new MemoryStream(imagem.Dados);
            return new FileStreamResult(ms, imagem.ContentType);
        }
    }
}

Para criar a view clique com o botão direito sobre o método Action Index e a seguir clique em Add View;

Aceite as definições conforme mostra a figura abaixo e clique em Add;

A seguir vamos definir o código na view para gerar o nosso arquivo PDF.

Definindo o código na view Index

Aqui colocamos o código para enviar a imagem e a seguir exibir a imagem enviada:

@model IList<int>
<h2>Enviar Imagens</h2>
<hr>
<form action="/Imagens/UploadImagem" enctype="multipart/form-data" method="post">
    <input type="file" name="arquivos" />
    <br />
    <button>Enviar Imagem</button>
</form>
<br />
@foreach (var item in Model)
{
   <img src="/Imagens/VerImagem/@item" />
}

Alterando o arquivo de leiaute

Vamos agora abrir o arquivo _Layout.cshml na pasta /Views/Shared e incluir o código em azul mostrado abaixo substituindo o código original:
   
...

<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-area="" asp-controller="Imagens" asp-action="Index">Enviar Imagens</a></li>

</ul>
</div>

...

Agora vamos alterar o código da view Index.cshtml da pasta Views/Home :

@{
    ViewData["Title"] = "Home Page";
}
<br />
<div>
    <h3>Gerar arquivos PDF</h3>
</div>

 

Fizemos isso somente para exibir um link para Enviar Imagens na página inicial.

Agora é só alegria...

Executando projeto iremos obter o seguinte resultado:

Vemos que podemos enviar imagens que são imediatamente exibidas na mesma página.

Pegue o código do projeto aqui:  AspNetCore_EnviaExibeImagem.zip

'Disse-lhe Jesus: Não te hei dito que, se creres, verás a glória de Deus? '
João 11:40

 

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