8

I am working on an MVC5 web application where I need to generate a report from any database table. The user will select the table he wants to print, then choose which columns to include in the report and the system should simply display a grid (table) with the data.

Displaying the data in a HTML table is of course not a problem and I have also managed to generate Excel files with the data, that the user can download.

However I also need to provide a printable form of the report such as PDF or some other format that doesn't need special software (such as MS Office) to open and print.

At first I thought I should go for the ReportViewer control, but the problem is that my report is dynamic since the user selects the columns he needs. I have seen attempts from others to generate the report definition file, but I was hoping for something less ugly.

Is there a way to take a HTML table, which calculates the sizing of the cells nicely, and create a PDF from it? I don't mind of course splitting the report horizontally in multiple pages if the columns are too many.

kagelos
  • 423
  • 8
  • 19
  • 1
    Since you already have HTML, I suggest that you take a look at iText's XMLWorker: http://developers.itextpdf.com/examples/xml-worker/html-tables. The examples are in Java but should be obvious enough for C#. iTextSharp is the .NET port of iText. Disclosure: I work at iText Software. – Amedee Van Gasse Feb 23 '16 at 12:45
  • Interesting. Can I somehow handle column fitting horizontally? I mean, if there are too many columns to fit in one page, can I move some of them to the next? – kagelos Feb 23 '16 at 13:32
  • @kagelos I have a solution which will do exactly want you want but it requires jquery. So can I use jquery and give you a solution? – Rajshekar Reddy Feb 26 '16 at 09:51
  • Sure, jQuery is fine. – kagelos Feb 26 '16 at 12:01

2 Answers2

2

You could try Spartacus.

It's a relatively new .NET library, totally written in C#. It can connect to many different databases and generate reports in Excel and PDF.

I uploaded 3 files in Google Drive:

In order to use Spartacus, you need to reference System.Data and System.Xml packages, as well as Spartacus.dll.

In the following example, I created report.pdf from template.xml in simple steps:

Spartacus.Database.Generic v_database;
Spartacus.Reporting.Report v_report;
System.Data.DataTable v_table;

v_database = new Spartacus.Database.Postgresql("127.0.0.1", "database", "postgres", "password");

v_table = v_database.Query(
    "select 'Example of Report made with Spartacus' as title, " +
    "       product, " +
    "       description, " +
    "       unit, " +
    "       quantity, " +
    "       total_cost, " +
    "       unit_cost " +
    "from table", "REPORT");

v_report = new Spartacus.Reporting.Report(1, "template.xml", v_table);
v_report.Execute();
v_report.Save("report.pdf");

Note that you don't need to use Spartacus.Database objects. If you can get a System.Data.DataTable by other means, then you can pass it to the Report object.

However, there is a catch. As you can see in the XML template, for each column, you need to know:

  • Column name (obviously)
  • Title
  • Align (LEFT, RIGHT or CENTER)
  • Fill (percent, 100 being the total width of the page minus width of the margins)
  • Type (INTEGER, REAL, BOOLEAN, CHAR, DATE or STRING)

Fill and Type are essential, and you may need to keep information about all your columns. If this is too hard to achieve, and you can only get column name and type, you can compute a aproximation based only on type, like the following:

  • product is of type STRING, default fill = 30
  • description is of type STRING, default fill = 30
  • unit is of type STRING, default fill = 30
  • quantity is of type REAL, default fill = 15
  • total_cost is of type REAL, default fill = 15
  • unit_cost is of type REAL, default fill = 15

The sum of all default fill are 30+30+30+15+15+15 = 135, greater than 100. So you can normalize to 100, this way:

  • Column fill = Column default fill * (sum of default fills / 100)

After that, you will need to generate dynamic template.xml files with dynamic field information.

DISCLAIMER: I'm Spartacus' creator and maintainer.

wind39
  • 441
  • 4
  • 14
  • Looks very nice. How can I handle cases where the columns don't fit in one page horizontally though? – kagelos Feb 29 '16 at 20:58
  • @kagelos Spartacus doesn't allow that. If you specify that a column has 30% of total width, it will always have 30% of total width. If the content doesn't fit in this space, then Spartacus cuts the content dynamically. – wind39 Feb 29 '16 at 21:05
0

SSRS has great support for automatically handling pagination, but following its rules are key.

Understanding Pagination in Reporting Services (Report Builder 3.0 and SSRS)

If you have designed a report to be one page wide, but it renders across multiple pages, check that the width of the report body, including margins, is not larger than the physical page size width. To prevent empty pages from being added to your report, you can reduce the container size by dragging the container corner to the left.

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
  • I believe you missed the most important part of the question, which is that the report's columns are added / removed dynamically. If it were a static report, or I was just interested in converting HTML to PDF I would not ask a question in the first place. I am looking for a solution where I can programmatically split the report horizontally into multiple pages. – kagelos Feb 24 '16 at 10:06
  • IMHO SSRS has the best support for that but you were not keen by the sounds of things. – Jeremy Thompson Feb 24 '16 at 10:08
  • @JeremyThompson How can I programmatically create a report in SSRS where I add the columns dynamically? As I mention in my question, the solutions I have seen so far attempt to create the definition file by printing (ugly) text / code. I would like to avoid this. – kagelos Feb 24 '16 at 10:10
  • It's tricky, I think you will have to leave it up to SSRS to handle splitting Tablixs over pages: http://stackoverflow.com/a/30858423 – Jeremy Thompson Feb 24 '16 at 10:16
  • @JeremyThompson still not what I am asking for. I need to be able to add columns to the report at runtime. I don't have an rdlc file a priori. – kagelos Feb 24 '16 at 10:22
  • Ok I can help you with that, I'll post code tomorrow (it's getting late here now). – Jeremy Thompson Feb 24 '16 at 10:28
  • Since the answer was changed after I posted my initial comment, it is no longer relevant, so I deleted my comment. – Amedee Van Gasse Feb 24 '16 at 11:05
  • Sorry to put you in that position @AmedeeVanGasse, as I learned more my original answer had become irrelevant – Jeremy Thompson Feb 24 '16 at 11:07