Neste artigo vou mostrar como podemos gerar relatórios no formato PDF usando o plugin Rotativa em aplicações ASP .NET MVC 5.
Para isso, vamos usar a biblioteca Rotativa que converte arquivos HTML para PDF usando a ferramenta wkhtmltopdf.exe para criar os arquivos PDF.
Essa ferramenta foi criada pelo italiano Giorgio Bozio, e a história você pode conferir neste link: http://letsfollowtheyellowbrickroad.blogspot.com.br/.
Para fazer esse trabalho, podemos usar na linha de comando as seguintes ferramentas: wkhtmltopdf e wkhtmltoimage que são open-source. (Veja o link: https://wkhtmltopdf.org/ )
Para usar na ASP .NET MVC 5, vamos instalar o pacote Rotativa em nosso projeto via Nuget. Instalaremos também a biblioteca PagedList para realizar a paginação.
A paginação em aplicações ASP .NET MVC já foi tratada no seguinte artigo:
Além disso, vamos usar o Entity Framework 6.x na abordagem Database-First para acessar um banco de dados SQL Server existente, chamado VendasDB.mdf, cuja estrutura é mostrada abaixo:

Vamos a seguir gerar um relatório de clientes, de pedidos e de vendas por período, mostrando os pedidos por cliente.
Para gerar o PDF, vamos usar a classe ViewAsPdf(), informando o nome da view e o nome do modelo que usaremos na view.
var relatorioPDF = new ViewAsPdf
{
ViewName = "RelatorioClientes",
Model = listaClientes.ToPagedList(pagNumero, listaClientes.Count)
};
return relatorioPDF;
Esta classe pode usar a propriedade CustomSwitches que pode receber comandos para formatar o cabeçalho e o rodapé.
var relatorioPDF = new ViewAsPdf
{
string comandos = string.Format
ViewName = "RelatorioClientes",
CustomSwitches = "--footer-center \"Nome: " + "XYZ" + " DOS: " +
DateTime.Now.Date.ToString("MM/dd/yyyy") + " Pag.: [page]/[toPage]\"" +
" --footer-line --footer-font-size \"9\" --footer-spacing 6 --footer-font-name \"calibri light\""
IsGrayScale = true,
Model = listaClientes.ToPagedList(pagNumero, listaClientes.Count)
};
return relatorioPDF;
A seguir, os principais comandos:
- –header-center \”texto\”: escreve um texto no cabeçalho. No caso, na região central do mesmo. Center pode ser substituído por right ou left;
- –header-spacing \”valor\”: determina o espaçamento do cabeçalho no início das páginas. Pode ser positivo ou negativo, passando assim a se sobrepor ao texto que não compõe o cabeçalho. Vale para para –footer-spacing \”valor\”;
- –header-font-name \”font\”: muda o tipo de fonte do cabeçalho. Vale também para –footer-font-name \”font\”;
- –header-font-size \”size\”: muda o tamanho da fonte a ser exibida no cabeçalho. Vale também para –footer-font-size \”size\”;
- –footer-right \”Pag: [page] de [toPage]\”: exibe a numeração das páginas do arquivo pdf. Pode ser usado no cabeçalho assim como ter sua posição e modos de escrita alterados.
Dito isso, vamos ao trabalho!

Recursos Usados
Criando o projeto no VS 2017
Abra o Visual Studio 2017 Community crie um novo projeto ASP .NET Web Application usando a linguagem C# e informe o nome Mvc5_RelatoriosPDF:

Use o template MVC sem autenticação e clique em “OK“:

Instalando o Entity Framework 6.x
Com o projeto criado, agora temos que referenciar o Entity Framework 6.x e definir no projeto, pois vamos usá-lo para acessar os dados no SQL Server.
No menu “Tools”, acione o Manage Nuget Package for Solutions, clique em “Browse” e localize o pacote EntityFramework. Marque o projeto e clique em “Install”:

Instalando as bibliotecas Rotativa e PagedList
Agora vamos instalar as bibliotecas Rotativa para gerar o PDF. Usaremos desta vez, o Package Manager Console para variar um pouco.
1- Instalando a biblioteca Rotativa
No menu Tools, abra a janela do Packabe Manager Console e a seguir digite o comando: install-package Rotativa.

Ao final, será criada no projeto uma pasta chamada Rotativa contendo os arquivos wkhtmltopdf.exe e wkimagetopdf.exe:

1- Instalando a biblioteca PagedList
No menu Tools, abra a janela do Packabe Manager Console e a seguir digite o comando: install-package PagedList.Mvc.

Pronto; todas as referências estarão definidas na pasta References do projeto, e agora já temos todos os recursos necessários para criar nossa aplicação ASP .NET MVC 5 e gerar relatórios no formato PDF.
Definindo o modelo de domínio
Em nosso modelo de domínio criaremos as classes que iremos usar para gerar o relatório.
Assim vamos criar as seguintes classes: Cliente e Pedido. Criaremos todas as classes na pasta Models do projeto via menu Project > Add Class.
1- Cliente
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace Mvc5_RelatoriosPDF.Models
{
[Table("Clientes")]
public class Cliente
{
public int ClienteId { get; set; }
public string Nome { get; set; }
public string Endereco { get; set; }
public string Email { get; set; }
public string Telefone { get; set; }
public virtual ICollection<Pedido> Pedidos { get; set; }
public Cliente()
{
Pedidos = new List<Pedido>();
}
}
}
2- Pedido
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace Mvc5_RelatoriosPDF.Models
{
[Table("Pedidos")]
public class Pedido
{
public int PedidoId { get; set; }
public int ClienteId { get; set; }
public DateTime PedidoData { get; set; }
public decimal PedidoTotal { get; set; }
}
}
Definindo a view model VendasViewModel
Agora vamos criar uma pasta chamada ViewModels em nosso projeto e criar nesta pasta uma classe chamada VendasViewModel, onde vamos definir uma view model para vendas. No menu “Project”, clique em “New Folder” e informe o nome ViewModels.
A seguir, crie a classe VendasViewModel nesta pasta com o seguinte código:
using System;
namespace Mvc5_RelatoriosPDF.ViewModels
{
public class VendasViewModel
{
public string ClienteNome { get; set; }
public string ClienteEmail { get; set; }
public DateTime PedidoData { get; set; }
public decimal PedidoTotal { get; set; }
}
}
Uma ViewModel representa apenas os dados que queremos exibir na view. Assim, se quisermos exibir mais de um modelo na view, precisamos criar um novo modelo para a view, que no exemplo é a classe VendasViewModel.
Definindo a string de conexão no arquivo web.config
Precisamos definir a string de conexão no arquivo web.config para informar ao EF onde está no banco de dados.
Abra o arquivo Web.Config do projeto e inclua o código abaixo:
... <connectionStrings> <add name="VendasDbContext" connectionString="Data Source=.\;Initial Catalog=VendasDB;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings> ...
Observe que o nome da string de conexão é o mesmo que o nome da nossa classe de Contexto: VendasDbContext.
Criando o controlador RelatoriosController e o relatório de clientes
Vamos criar um controlador RelatoriosController na pasta Controllers e inicialmente vamos gerar o relatório para clientes e depois para pedidos.
Clique com o botão direito sobre a pasta Controllers, e a seguir clique em Add Controller, e em seguida selecione o template MVC 5 Controller – Empty e informe o nome RelatoriosController.
A seguir vamos substituir o método Action Index pelo método RelatorioClientes() conforme mostra o código a seguir:
using Mvc5_RelatoriosPDF.Models;
using PagedList;
using Rotativa;
using System;
using System.Linq;
using System.Web.Mvc;
namespace Mvc5_RelatoriosPDF.Controllers
{
public class RelatoriosController : Controller
{
private VendasDbContext db = new VendasDbContext();
public ActionResult RelatorioClientes(int? pagina, Boolean? pdf)
{
var listaClientes = db.Clientes.OrderBy(c =>c.ClienteId ).ToList();
if (pdf != true)
{
int numeroRegistros = 3;
int numeroPagina = (pagina ?? 1);
return View(listaClientes.ToPagedList(numeroPagina, numeroRegistros));
}
else
{
int pagNumero = 1;
var relatorioPDF = new ViewAsPdf
{
ViewName = "RelatorioClientes",
IsGrayScale = true,
Model = listaClientes.ToPagedList(pagNumero, listaClientes.Count)
};
return relatorioPDF;
}
}
}
}
Neste código criamos uma instância do nosso contexto VendasDbContext para usar no acesso e persistência das informações.
A view recebe dois parâmetros: página e pdf que indicam o número da página e se vamos gerar o relatório no formato PDF.
Se pdf for false ou null, passamos uma relação de clientes obtidas e ordenadas pelo Id do cliente usando o PagedList(). Dessa forma, teremos uma view tipada usando PagedList que via realizar a paginação. Caso contrário, usamos a classe ViewAsPdf para gerar o PDF a partir da view. No código estamos informando:
- ViewName: nome da view que será usada para gerar o PDF;
- Model: nome do model usado na view. No exemplo, passamos a lista de clientes com PagedList;
- IsGrayScale: indica se usamos uma escala de cinza.
Agora vamos criar a View RelatorioClientes para exibir a lista de clientes. Nesta view vamos definir um link para poder gerar o PDF.
Clique com o botão direito do mouse sobre o método Action RelatorioClientes, e a seguir clique em “Add View“, aceite o nome padrão e escolha o template List e Model Cliente, conforme a figura abaixo.

Clique no botão “Add” e a seguir altere o código da view gerada conforme abaixo:
@model PagedList.IPagedList<Mvc5_RelatoriosPDF.Models.Cliente>
<h2>Relação de Clientes</h2>
<table class="table">
<tr>
<th>Nome</th>
<th>Endereço</th>
<th>Email</th>
<th>Telefone</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Nome)
</td>
<td>
@Html.DisplayFor(modelItem => item.Endereco)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Telefone)
</td>
</tr>
}
<tr>
<td><b>@Model.Count registros de @Model.TotalItemCount</b></td>
<td><a href="/Relatorios/RelatorioClientes?pdf=true"><b>Gerar Relatório em PDF</b></a></td>
</tr>
</table>
<!--páginação de dados -->
@{
if (Model.TotalItemCount != Model.Count)
{
<div class="row">
<div class="col-md-12">
Página @(Model.PageCount<Model.PageNumber? 0 : Model.PageNumber) de @Model.PageCount
@if (Model.HasPreviousPage)
{
@Html.ActionLink("<<", "RelatorioClientes", new { pagina = 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
@Html.Raw(" ");
@Html.ActionLink("< Anterior", "RelatorioClientes", new { pagina = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter})
}
else
{
@:<<
@Html.Raw(" ");
@:< Anterior
}
@if(Model.HasNextPage)
{
@Html.ActionLink("Próxima >", "RelatorioClientes", new { pagina = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
@Html.Raw(" ");
@Html.ActionLink(">>", "RelatorioClientes", new { pagina = Model.PageCount, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
}
else
{
@:Próxima >
@Html.Raw(" ")
@:>>
}
</div>
</div>
}
}
Nesta view, além da página que já expliquei em detalhes em outro artigo, temos um link que aciona a view para gerar o PDF : /Relatorios/RelatorioClientes?pdf=true”.
Criando o relatório de pedidos
O relatório de pedidos é igualzinho ao de clientes, por isso, basta repetir todo o procedimento acima para pedidos, então primeiro crie um método Action RelatorioPedidos e a seguir a view RelatorioPedidos.
Abaixo temos o código do método Action RelatorioPedidos:
public ActionResult RelatorioPedidos(int? pagina, Boolean? pdf)
{
var listaPedidos = db.Pedidos.OrderBy(c => c.PedidoId).ToList();
if (pdf != true)
{
int numeroRegistros = 5;
int numeroPagina = (pagina ?? 1);
return View(listaPedidos.ToPagedList(numeroPagina, numeroRegistros));
}
else
{
int pagNumero = 1;
var relatorioPDF = new ViewAsPdf
{
ViewName = "RelatorioPedidos",
IsGrayScale = true,
Model = listaPedidos.ToPagedList(pagNumero, listaPedidos.Count)
};
return relatorioPDF;
}
}
O código da view RelatorioPedidos segue abaixo:
@model PagedList.IPagedList<Mvc5_RelatoriosPDF.Models.Pedido>
@{
ViewBag.Title = "RelatorioPedidos";
}
<h2>Relação de Pedidos</h2>
<table class="table">
<tr>
<th>
Id Cliente
</th>
<th>
Data Pedido
</th>
<th>
Total do Pedido
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ClienteId)
</td>
<td>
@Html.DisplayFor(modelItem => item.PedidoData)
</td>
<td>
@Html.DisplayFor(modelItem => item.PedidoTotal)
</td>
</tr>
}
<tr>
<td><b>@Model.Count registros de @Model.TotalItemCount</b></td>
<td><a href="/Relatorios/RelatorioPedidos?pdf=true"><b>Gerar Relatório em PDF</b></a></td>
</tr>
</table>
<!--paginação de dados -->
@{
if (Model.TotalItemCount != Model.Count)
{
<div class="row">
<div class="col-md-12">
Página @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) de @Model.PageCount
@if (Model.HasPreviousPage)
{
@Html.ActionLink("<<", "RelatorioPedidos", new { pagina = 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
@Html.Raw(" ");
@Html.ActionLink("< Anterior", "RelatorioPedidos", new { pagina = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
}
else
{
@:<<
@Html.Raw(" ");
@:< Anterior
}
@if (Model.HasNextPage)
{
@Html.ActionLink("Próxima >", "RelatorioPedidos", new { pagina = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
@Html.Raw(" ");
@Html.ActionLink(">>", "RelatorioPedidos", new { pagina = Model.PageCount, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter })
}
else
{
@:Próxima >
@Html.Raw(" ")
@:>>
}
</div>
</div>
}
}
Executando o projeto iremos obter o seguinte resultado:
1- A relação de clientes com paginação e o link para gerar PDF

2- O relatório PDF dos clientes

Se desejar salvar o relatório, basta clicar no botão download.
Para gerar o relatório como um arquivo diretamente, basta definir a propriedade FileName da classe ViewAsPdf no controlador, atribuindo um nome para o relatório gerado:
var relatorioPDF = new ViewAsPdf
{
ViewName = "RelatorioClientes",
IsGrayScale = false,
FileName = "RelatorioClientesPDF",
Model = listaClientes.ToPagedList(pagNumero, listaClientes.Count)
};
return relatorioPDF;
Na próxima parte do artigo veremos como gerar o relatório de vendas por período que um pouco mais complexo.
Pegue o projeto completo no link a seguir:
- Mvc5_RelatoriosPDF.zip (sem as referências e os arquivos da pasta rotativa).




