Как загрузить отчет в формате PDF используя FastReport Core

18.09.2017

В этой статье мы продолжим тему “FastReport Core + .Net Core”. В предыдущей статье мы рассмотрели, как отображать отчет с помощью экспорта в формат html. Теперь я покажу, как организовать загрузку отчета из браузера на локальный компьютер с помощью кнопки. В качестве конечного файла мы будет использовать экспорт в PDF (можно и любой другой). На этот раз мы будем использовать базу данных SQLite.

Создаем проект ASP .Net Core Web Application. Подключаем библиотеки:

FastReport Core, Microsoft.EntitiyFrameworkCore.Sqlite, Microsoft.EntitiyFrameworkCore.Sqlite.Design. В итоге вы должны иметь следующие установленные пакеты:

Давайте предварительно поработаем с данными. Нам потребуется база данных SQLite – fastreport.db. Ее можно взять в демонстрационном проекте «С:\Program Files (x86)\FastReports\FastReport.Net\Demos\Core\FastReportCore.MVC». Добавляем базу данных прямо в корень проекта. Также, добавим в проект шаблон отчета “Simple List.frx” из папки «С:\Program Files (x86)\FastReports\FastReport.Net\Demos\Reports»

Теперь, в папку Models добавим новый класс. Назовем его ApplicationDbContext.cs. Как вы поняли из названия – это контекст данных. Вот его содержание:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using Microsoft.EntityFrameworkCore;
using System;
using System.Data;
using System.Reflection;
 
namespace FRCore
{
 public class ApplicationDbContext : DbContext
 {
 public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
 : base(options)
 { }
 
 public ApplicationDbContext()
 {
 
 }
 
 public DbSet<Employees> Employees { get; set; }
 
//Получаем набор данных
 public DataSet GetDataSet(string name)
 {
 DataSet set = new DataSet(name);
 set.Tables.Add(GetTable(Employees, "Employees"));
 return set;
 }
 
//Задаем первичный ключ
 protected override void OnModelCreating(ModelBuilder modelBuilder)
 {
 modelBuilder.Entity<Employees>(entity =>
 {
 entity.HasKey(e => e.EmployeeId)
 .HasName("sqlite_autoindex_employees_1");
 });
 }
 
//Задаем источник данных
 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
 optionsBuilder.UseSqlite(@"data source= fastreport.db");
 }
 
//Получаем таблицу нужную для формироания отчета. По сути метод преобразования IQuerable в DataTable
 static DataTable GetTable<TEntity>(DbSet<TEntity> table, string name) where TEntity : class
 {
 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
 row[info.Name] = info.GetValue(el);
 result.Rows.Add(row);
 }
 return result;
 }
 }
 
//Модель таблицы Employees
 public class Employees
 {
 public int EmployeeID { get; set; }
 public int EmployeeId { get; set; }
 public string LastName { get; set; }
 public string FirstName { get; set; }
 public string Title { get; set; }
 public string TitleOfCourtesy { get; set; }
 public System.DateTime? BirthDate { get; set; }
 public System.DateTime? HireDate { get; set; }
 public string Address { get; set; }
 public string City { get; set; }
 public string Region { get; set; }
 public string PostalCode { get; set; }
 public string Country { get; set; }
 public string HomePhone { get; set; }
 public string Extension { get; set; }
 public byte[] Photo { get; set; }
 public string Notes { get; set; }
 public int? ReportsTo { get; set; }
 }
}

В этом классе мы соединяемся с базой данных, получаем набор данных и преобразовываем его в DataTable, которая нужна для FastReport чтобы сгенерировать отчет. Модель таблицы Employees, которая будет использована в отчете, представлена отдельным классом.

Переходим к редактированию HomeController.cs. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using FRCore.Models;
using FastReport;
using FastReport.Export.Html;
using System.IO;
using System.Text;
using FastReport.Export.Pdf;
using System.Data;
 
namespace FRCore.Controllers
{
 public class HomeController : Controller
 {
 public Report report = new Report();
 
 private ApplicationDbContext _context = new ApplicationDbContext();
 
 public ApplicationDbContext GetContext()
 {
 return _context;
 }
 
 public IActionResult Index()
 {
 DataSet dataSet = new DataSet();
 dataSet = GetContext().GetDataSet("NorthWind");
 report.Report.RegisterData(dataSet, "NorthWind");
 report.Report.Load("Simple List.frx");
 report.Prepare();
 
 HTMLExport export = new HTMLExport();
 export.Layers = true;
 using (MemoryStream ms = new MemoryStream())
 {
 export.EmbedPictures = true;
 export.Export(report, ms);
 ms.Flush();
 ViewData["Report"] = Encoding.UTF8.GetString(ms.ToArray());
 ViewData["ReportName"] = "Simple List.frx";
 }
 return View();
 }
 
 public IActionResult Pdf()
 {
 System.Data.DataSet dataSet = new System.Data.DataSet();
 dataSet = GetContext().GetDataSet("NorthWind");
 report.Report.RegisterData(dataSet, "NorthWind");
 report.Report.Load("Simple List.frx");
 report.Prepare();
 
 PDFExport export = new PDFExport();
 using (MemoryStream ms = new MemoryStream())
 {
 export.Export(report, ms);
 ms.Flush();
 return File(ms.ToArray(), "application/pdf", Path.GetFileNameWithoutExtension("Simple List") + ".pdf");
 }
 }
 }
}

Метод Index просто отображает отчет в формате html, а метод PDF – формирует PDF файл для загрузки. Оба метода используют контекст данных для отчета.

Теперь изменим представление Index.cshtml:

1
2
3
4
5
6
7
8
9
10
11
@{
 ViewData["Title"] = "Home Page";
}
@if (ViewData.ContainsKey("ReportName"))
{
 <a class="btn btn-danger" asp-controller="Home" asp-action="Pdf" asp-route-report="@ViewData["ReportName"]">Download PDF</a>
}
@if (ViewData.ContainsKey("Report"))
{
 @Html.Raw(ViewData["Report"])
}

Мы добавили кнопку загрузки PDF сначала. Затем – отображаем отчет.

Запустим наше приложение:

Нажимаем кнопку «Download PDF». И скачиваем файл отчета в формате PDF. Реализация довольно проста, не сложнее чем отобразить отчет.

1 ноября 2024

Новые возможности редактора отчетов FastReport VCL

Рассматриваем новые возможности редактора отчетов: выносные линии, подсветка пересекающихся объектов, обновлённые деревья отчетов и данных.
30 октября 2024

Использование стилей при создании отчетов в FastReport VCL

В статье подробно рассматривается одна из новых возможностей FastReport VCL – применение стилей и страниц стилей.
28 октября 2024

Как настроить WSL 2 для работы с FastReport и FastCube

В этой статье попробуем вместе разобраться, как настроить WSL 2 для работы с компонентами FastReport и FastCube в Lazarus для Linux.