ASP.NET Core - Gerando relatórios com FastReport - III
 Neste artigo vamos continuar mostrando como gerar relatórios em uma aplicação ASP .NET Core MVC usando o FastReport.


Continuando a segunda parte do artigo vamos agora realizar a integração do relatório gerado no artigo anterior com a aplicação ASP.NET Core MVC que foi criada no primeiro artigo.

 


 


 

Integrando o relatório com a aplicação MVC

 

Já temos a aplicação MVC - WebFastReport - criada com os pacotes do FastReport e do Entity Framework referenciados.
 

Precisamos agora incluir o novo pacote : FastReport.OpenSource.Data.MsSql  para gerenciar a conexão com o SQL Server.


Já temos a string de conexão com o banco de dados Northwind já configura no arquivo appsettings.json:


Vamos incluir na pasta Models a classe Category contendo as propriedades que serão acessadas :

 

namespace WebFastReport.Models;

public class Category
{
    public int CategoryID { get; set; }
    public string? CategoryName { get; set; }
    public string? Description { get; set; }
    public byte[]? Picture { get; set; }
}

Também vamos incluir na interface IProductService o contrato para retorna todas as Categorias:

using WebFastReport.Models;

namespace WebFastReport.Services;

public interface IProductService
{
    List<Product> GetProducts();
    List<Category> GetCategories();
}

 

Na classe ProductService vamos incluir a implementação do método GetCategories:

 

using WebFastReport.Models;

namespace WebFastReport.Services;

public class ProductService : IProductService
{
    private readonly AppDbContext _context;
    public ProductService(AppDbContext context)
    {
        _context = context;
    }

    public List<Product> GetProducts()
    {
        var products = _context.Products.ToList();
        return products;
    }

  public List<Category> GetCategories()
  {
    
var categories = _context.Categories.ToList();
    
return categories;
  }

}

Vamos incluir no arquivo Program o registro do objeto do tipo MsSqlDataConnection e incluir o middeware do FastReports:

using Microsoft.EntityFrameworkCore;
using WebFastReport.Models;
using WebFastReport.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

FastReport.Utils.RegisteredObjects.AddConnection(typeof(MsSqlDataConnection));

var con = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options =>
             options.UseSqlServer(con));

builder.Services.AddScoped<IProductService, ProductService>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseFastReport();

app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

 

Todas essas configurações foram feitas para acessar os dados via EF Core. Vamos agora usar o controlador e definir a geração do relatório para categorias e a geração do PDF

 

Gerando o relatório

 

No controlador HomeController vamos criar o método Action Report para exibir o relatório de Categorias no navegador:
 

[Route("Report")]
public IActionResult Report()
{
   var webReport = new WebReport();
  
var mssqlDataConnection = new MsSqlDataConnection();

    mssqlDataConnection.ConnectionString =
   _configuration.GetConnectionString(
"DefaultConnection");

    webReport.Report.Dictionary.Connections.Add(mssqlDataConnection);

    webReport.Report.Load(Path.Combine(_webHostEnv.ContentRootPath,
                    "wwwroot/reports
", "CategoriesReport.frx"));

   
var categories = GetTable<Category>(
             _productService.GetCategories(),
"Categories");

    webReport.Report.RegisterData(categories,
"Categories");

   
return View(webReport);
}


O método GetTable<Category>() é um método estático usado para retornar um DataTable com os dados das categorias:

 

static DataTable GetTable<TEntity>(IEnumerable<TEntity> table, string name) where TEntity : class
    {
        var offset = 78;
        DataTable result = new DataTable(name);
        PropertyInfo[] infos = typeof(TEntity).GetProperties();
        foreach (PropertyInfo info in infos)
        {
            if (info.PropertyType.IsGenericType &&
                info.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                result.Columns.Add(new DataColumn(info.Name, Nullable
                                                                       .GetUnderlyingType(info.PropertyType)));
            }
            else
            {
                result.Columns.Add(new DataColumn(info.Name, info.PropertyType));
            }
        }
        foreach (var el in table)
        {
            DataRow row = result.NewRow();
            foreach (PropertyInfo info in infos)
            {
                if (info.PropertyType.IsGenericType &&
                    info.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    object t = info.GetValue(el);
                    if (t == null)
                    {
                        t = Activator.CreateInstance(Nullable.GetUnderlyingType(info.PropertyType));
                    }

                    row[info.Name] = t;
                }
                else
                {
                    if (info.PropertyType == typeof(byte[]))
                    {
                        var imageData = (byte[])info.GetValue(el);
                        var bytes = new byte[imageData.Length - offset];
                        Array.Copy(imageData, offset, bytes, 0, bytes.Length);
                        row[info.Name] = bytes;
                    }
                    else
                    {
                        row[info.Name] = info.GetValue(el);
                    }
                }
            }
            result.Rows.Add(row);
        }
        return result;
    }

 

Precisamos criar a view Report.cshtml com o código a seguir:
 

@model FastReport.Web.WebReport

@{
    ViewData[
"Title"] = "Categories - Report";
}

@await Model.Render()
 

Gerando o arquivo PDF

Para gerar o arquivo PDF com os dados das categorias vamos incluir o método Action CategoriesReport :

    [Route("CategoriesReport")]
    public IActionResult CategoriesReport()
    {
        var webReport = new WebReport();
        var mssqlDataConnection = new MsSqlDataConnection();

        mssqlDataConnection.ConnectionString =
                _configuration.GetConnectionString("DefaultConnection");

        webReport.Report.Dictionary.Connections.Add(mssqlDataConnection);

        webReport.Report.Load(Path.Combine(
       _webHostEnv.ContentRootPath, "wwwroot/reports", "CategoriesReport.frx"));

        var filteredCategories = _productService.GetCategories();
        var categories = GetTable<Category>(filteredCategories, "Categories");
        webReport.Report.RegisterData(categories, "Categories");
        webReport.Report.Prepare();

        Stream stream = new MemoryStream();
        webReport.Report.Export(new PDFSimpleExport(), stream);
        stream.Position = 0;
        // retorna o stream no navegador
        return File(stream, "application/zip", "report.pdf");
    }

A seguir vamos ajustar o arquivo _Layout.cshtml para exibir as opções para gerar os relatórios :

...
  <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
        <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="Home" asp-action="CreateReport">Create Report</a>
           </li>
           <li class="nav-item">
               <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="ProductsReport">Products PDF </a>
            </li>
           <li class="nav-item">
              <a class="nav-link text-dark" asp-area=""
                    asp-controller="Home" asp-action="Report">Categories Report</a>
           </li>
          <li class="nav-item">
               <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="CategoriesReport">Categories PDF </a>
          </li>
        </ul>
   </div>
...

 

Agora é só alegria...

 

Executando o projeto e acionando as opçõs Categories Report e Categoreis PDF teremos o resultado a seguir:

 


 

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

No próximo artigo vamos integrar o relatório com a ASP.NET Core Web API.
 

"(Disse Jesus) Em verdade, em verdade vos digo que vem a hora e já chegou, em que os mortos ouvirão a voz do Filho de Deus; e os que a ouvirem viverão."
João 5:25

Porque um menino nos nasceu, um filho se nos deu, e o principado está sobre os seus ombros, e se chamará o seu nome: Maravilhoso, Conselheiro, Deus Forte, Pai da Eternidade, Príncipe da Paz.

Isaías 9:6
Porque um menino nos nasceu, um filho se nos deu, e o principado está sobre os seus ombros, e se chamará o seu nome: Maravilhoso, Conselheiro, Deus Forte, Pai da Eternidade, Príncipe da Paz.

Isaías 9:6

Referências:


José Carlos Macoratti