Bonjour,
Je travaille sur une librairie qui puisse permettre, depuis une page ASPX, de générer à la volée un document PDF en lui passant en paramètre :
- Une série de paramètres
- Le nom d'un rapport RDLC ou RDL présent sur le serveur
Pour le moment, j'ai fait un truc qui marche plutôt pas mal, mais il est à mon avis largement perfectible.
Le code en l'état :
PageRDLtoPDF.aspx
Code html : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 <%@ Page Language="C#" AutoEventWireup="true" Inherits="CustomPages.PageRDLtoPDF" %>
PageRDLtoPDF.aspx.cs
Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
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 using My.Editions; using System; using System.IO; using update.Web.Pages; namespace CustomPages { public class PageRDLtoPDF : BasePage { public PageRDLtoPDF() { } protected void Page_Load(object sender, EventArgs e) { Response.Clear(); Response.ContentType = "application/pdf"; IniFile iniFile = new IniFile(Server.MapPath("~/system/sys/mmdb.ini")); MemoryStream memoryStream = new MemoryStream(); RDLtoPDF edition = new RDLtoPDF(iniFile.keys["CnxString"], iniFile.keys["TblPrefix"], Server.MapPath("~/"), Request.Form["Records"], Request.Form["ReportName"]); edition.Edition(memoryStream); memoryStream.WriteTo(Response.OutputStream); Response.Flush(); Response.Close(); Response.End(); } } }
RDLtoPDF.cs
Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
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 using System.Collections.Generic; using System.Data; using System.Data.Odbc; using System.IO; using Microsoft.Reporting.WinForms; namespace My.Editions { public class RDLtoPDF : IEdition { private readonly string CnxString; private readonly string TblPrefix; private readonly string Path; private readonly string ReportName; private readonly string RecordsId; public RDLtoPDF(string cnxString, string tblPrefix, string path, string recordsId, string reportName) { CnxString = cnxString; TblPrefix = tblPrefix; Path = path; ReportName = $"{Path}\\my_ssrs\\{reportName}"; RecordsId = recordsId; } public void Edition(Stream output) { if (RecordsId.Length > 0) { using (OdbcConnection cnx = new OdbcConnection(CnxString)) { cnx.Open(); using (OdbcCommand cmd = cnx.CreateCommand()) { ReportViewer viewer = new ReportViewer(); viewer.LocalReport.Refresh(); viewer.LocalReport.ReportPath = ReportName; IList<string> Queries = viewer.LocalReport.GetDataSourceNames(); cmd.CommandTimeout = 120; foreach (string query in Queries) { cmd.CommandText = string.Format(File.ReadAllText(string.Concat($"{Path}\\my_ssrs\\{query}.sql")), TblPrefix, RecordsId); cmd.Prepare(); DataSet ds = new DataSet(); OdbcDataAdapter da = new OdbcDataAdapter(cmd); da.Fill(ds); ReportDataSource rds = new ReportDataSource(query, ds.Tables[0]); viewer.LocalReport.DataSources.Add(rds); } viewer.LocalReport.SubreportProcessing += LocalReport_SubreportProcessing; byte[] bytes = viewer.LocalReport.Render("PDF", null, out string mimeType, out string encoding, out string extension, out string[] streamIds, out Warning[] warnings); output.Write(bytes, 0, bytes.Length); } cnx.Close(); } } } private void LocalReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e) { using (OdbcConnection cnx = new OdbcConnection(CnxString)) { cnx.Open(); using (OdbcCommand cmd = cnx.CreateCommand()) { foreach (ReportParameterInfo p in e.Parameters) { cmd.Parameters.AddWithValue(p.Name, p.Values[0]); } foreach (string query in e.DataSourceNames) { cmd.CommandText = string.Format(File.ReadAllText(string.Concat($"{Path}\\my_ssrs\\{query}.sql")), TblPrefix); cmd.Prepare(); DataSet ds = new DataSet(); OdbcDataAdapter da = new OdbcDataAdapter(cmd); da.Fill(ds); ReportDataSource rds = new ReportDataSource(query, ds.Tables[0]); e.DataSources.Add(rds); } } cnx.Close(); } } } }
La partie sur les sous-rapport, pour le moment je ne l'ai pas testée.
En revanche, le reste fonctionne.
Si j'ai un rapport avec 3 datasource, ma page arrive à retrouver le nom de ces trois datasource, ainsi que les paramètres.
En revanche, je n'arrive pas à récupérer le SQL des datasources présents dans le rapport.
Du coup je suis obligé de passer par des fichiers SQL stockés à côté, portant le nom des datasets.
C'est un peu crade, et j'aimerais plutôt récupérer les requêtes telles qu'existantes dans le rapport.
Avez-vous une idée de comment faire ?
Autre solution, mais pas forcément meilleure pour moi : exécuter directement le rapport en lui passant les paramètres, sans avoir à me soucier de la liaison aux données.
Seul hic, entre DEV, TEST et PROD ça m'obligerait à maintenir 3 versions différentes des mêmes rapports, ce qui ne me semble pas terrible !
(Là, je retrouve la chaîne de connexion à la base à partir d'un fichier INI trouvé dans un dossier de l'application appelante).
Partager