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.