В этой статье мы продолжим тему “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. Реализация довольно проста, не сложнее чем отобразить отчет.