In this article we will continue covering the topic "FastReport Core + .Net Core". In the previous article we have illustrated how to display a report by exporting it to the HTML format. Now I will show how to organize downloading of a report from a browser to a local computer, using a button. We will use the export to PDF (you can use any other formats) Â in the function of the final file. This time it will be the SQLite database.
First, create an ASP.NET Core Web Application project and add the following libraries:
FastReport Core, Microsoft.EntitiyFrameworkCore.Sqlite, Microsoft.EntitiyFrameworkCore.Sqlite.Design. As a result, you will have the following installed packages:
Let us work with the data in advance. We need the SQLite database - fastreport.db. It can be taken from the demonstration project "C:\ Program Files (x86)\FastReports\FastReport.Net\Demos\Core\FastReportCore.MVC". Add the database directly to the root of the project. Also, we add a report template "Simple List.frx" from the folder "C:\Program Files (x86)\FastReports\FastReport.Net\Demos\Reports" to the project.
Now, in the Models folder, add a new class. We call it ApplicationDbContext.cs. As you might have understood from the title - this is the data context. Here is its content:
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; } Â // Get the data set public DataSet GetDataSet(string name) { DataSet set = new DataSet(name); set.Tables.Add(GetTable(Employees, "Employees")); return set; } Â // Set the primary key protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Employees>(entity => { entity.HasKey(e => e.EmployeeId) .HasName("sqlite_autoindex_employees_1"); }); } Â // Set the data source 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"); } Â // Get the table you need to create a report. In fact, the method of converting IQuerable into a 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; } } Â // The Employees table model 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; } } } |
In this class, after connecting to the database, we get a set of data and convert it to a DataTable, which is needed for FastReport to generate the report. The model of the Employees table, that will be used in the report, is represented by a separate class.
Now go to edit 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"); } } } } |
The Index method simply displays the report in HTML format, whereas the PDF method generates a PDF file for downloading. Both methods use the data context for reports.
Now change the presentation of 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"]) } |
We have first added a PDF download button. Then, we displayed the report.
Run our application:
Â
The article has intoduced a model of how to organize a downloading process of a report from a browser to a local computer, using a button. We just press the "Download PDF" button and download the report file in PDF format. The procedure is as simple as displaying a report.