I've done a asp.net application to generate reports over a particular data. Initially i created local reports (.rdlc) to generate reports. I created separate .xsd for each rdlc and designed the reports. I build the dataset programmatically and bind it to the rdlc. I used the following code for binding the datasource to the reports -
rptMyReport.LocalReport.ReportPath = Server.MapPath(srdlcName);
rptMyReport.LocalReport.DataSources.Add(rds);
Now i have converted all the rdlc to rdl following this msdn article and i've published the reports to the report server.
rptMyReport.ServerReport.ReportServerUrl = new System.Uri("http://ReportServer/ReportServer");
rptMyReport.ServerReport.ReportPath = "/ReportFolder/ReportName";
Now how can i set the datasource to the reports programmatically?
This work is impossible. you should create your datasource in your rdl report. you must write needed queries for report data gathering. you can use this query as a text or stored procedure. You can pass parameters to this query and filter the output of the query.
you can only pass the parameters to rdl report like this:
ReportParameter[] Params = new ReportParameter[1];
Params[0] = "Parameter Value";
ReportViewerControl.ServerReport.SetParameters(Params);
What are you trying to do? I believe the datasource is mentioned within the .RDL file itself.
For ex: When you create an Report using BIDS, you can specify the datasource. This gets added to the .RDL file. The same concept holds true here as well.
This is not impossible, but may take a little effort if this is what you want to do.
You have a couple of options:
If you create a shared datasource on your report server you can add it manually using the RDLObjectModel. Get the shared datasource name and guid from your reportserver and you can add it to your report.
Example:
'create the datasource for the report
Dim dataSrcRFoo = New RdlObjectModel.DataSource
dataSrcRFoo.Name = "DataSourceName"
dataSrcRFoo.DataSourceReference = "/path/to/DataSource"
dataSrcRFoo.IsShared = True
dataSrcRFoo.SecurityType = 2 ' RdlObjectModel.SecurityTypeEnum.DataBase
dataSrcRFoo.DataSourceID = New Guid("shareddatasourceguid")
'add data source to report
rdlRpt.DataSources.Add(dataSrcRFoo)
Another option is to use templates on the server that have the share (or report level) datasource built in.
Related
How do i send 3 datatable to the StimulSoft report in winforms c#.
I added dataset and 3 Datatable in StimulSoft report.
I typed in app:
StiReport report = new StiReport();
string fileReport = "Report\\ReportTest.mrt";
string myfile = System.AppDomain.CurrentDomain.BaseDirectory + fileReport;
report.Load(myfile);
report.Compile();
report.RegData(dtDelay);
report.RegData(dtDesc);
report.RegData(dtPart);
report.Show();
Sample App
Please use my method in this post :
Customiz (or Create) a table(StiTable) at runtime in C# (.NET4)
You can call this method as many times as you want.
Note that you can adjust the method and take the table name or view from code and make it dynamic , after it you can create as many tables as you want. Use the method before comlie() method.
I have 2 parameters (Detail, Summary) that I have created in a Crystal Report. The report is called from c# in a Windows Forms application. I am trying to pass the appropriate value to each parameter at runtime so the report can make some decisions based on the values. I have read many articles regarding this and I think I am using the best method to accomplish this?
This is the simple code I have implemented after the report has been loaded and before the SetDataSoruce has been set:
crReportDocument.SetParameterValue("DetailView", false);
crReportDocument.SetParameterValue("SummaryView", true);
For some reason the values are not getting to the report as the report is always prompting for the values to be set when it runs.
Everything else about the report works correctly.
I would appreciate any light someone can shed on this matter as it seems to be a simple task to do?
Actually the problem was code placement. I was populating the parameters in the wrong place of code execution:
This is how I had it when it was not working:
crReportDocument.SetParameterValue("FromDate", dtmFromDate);
ReportViewer reportViewer = new ReportViewer();
reportViewer.ReportSource = crReportDocument;
To resolve I moved the code around as follows:
ReportViewer reportViewer = new ReportViewer();
reportViewer.ReportSource = crReportDocument;
crReportDocument.SetParameterValue("FromDate", dtmFromDate);
That's all it took to get it to work correctly.
Let me know if it does not work for you.
The problem is that the parameter must be passed using format {?PARAMETER}.
It works.
crReportDocument.SetParameterValue("{?DetailView}", false);
crReportDocument.SetParameterValue("{?SummaryView}", true);
I have an MDI application with many different Forms. Then I have a ReportViewer control inside a ReportForm where I dynamically load RDLC reports.
The ReportForm is opened from the other Forms with a button click.
Inside the ReportForm, above the ReportViewer control, there's a ComboBox with a list of available reports for that specific Form. That list is dynamically generated based on the Form from which the ReportViewer was opened.
The list is generated by looking for a Form associated folder, inside the Reports Project (which output is a DLL), that contains the corresponding .rdlc files.
The question is this:
Since the RDLC are all already generated and configured with Report Designer and binded to specific DataSet and DataTable, why do I need to recreate everytime the ReportDataSource object (DataSet, DataTable) and rebind it to the report?
My actual code:
// Code used to open a new ReportForm Window
private void bindingNavigatorViewReport_Click(object sender, EventArgs e)
{
// If the form is already open, then Focus on it
if (MdiMain.IsFormOpen(ApplicationForm.ReportForm))
{
Application.OpenForms[formName].Focus();
}
// I need to instantiate a new ReportForm
else
{
/* The parameters are:
* - ApplicationForm enum which identifies the Form;
* - The Form corresponding DataSet
*/
ReportForm reportForm = new ReportForm(ApplicationForm.SchoolForm, SchoolDataSet)
{
MdiParent = MdiParent,
Icon = Resources.ViewReportIcon
};
reportForm.Show();
}
}
// Code used to load report
/* In the ReportForm class I have a method that casts the parameters to the
* specific types. So I can obtain the DataSet to use.
*/
// Report Path inside DLL assembly taken from SelectedValue of ComboBox
string reportSource = cmbReport.SelectedValue.ToString();
// Get report Stream from DLL Path
Stream reportStream = assembly.GetManifestResourceStream(reportSource);
// Load report Stream
reportViewer1.LocalReport.LoadReportDefinition(reportStream);
/* Create a new DataSource with DataSet name and DataTable object
* The DataTable object must come from DataSet, ie: DataSet.SchoolListDataTable.
*/
ReportDataSource rds = new ReportDataSource("DataSetName", DataTableObject);
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(rds);
reportViewer1.LocalReport.Refresh();
The main problem is that I have no "dynamic way" to get from the Forms the DataTable object for every report associated to the Form, since when I click on the "Open report window" button, I have a list of reports and so on DataSet (associated to that Form) but many different DataTables, not just one.
** UPDATE: Final solution **
Finally I found that when I load the report stream I can use this code:
// Loads all the data sources associated to the current selected report
IEnumerable<string> dsNames = reportViewer1.LocalReport.GetDataSourceNames();
foreach (string dsName in dsNames)
{
// dsName is equal to the string "V_REP_SCHOOLS" that is the corresponding DataTable name
ReportDataSource rds = new ReportDataSource(dsName, _currentReportDataSet.Tables[dsName]);
reportViewer1.LocalReport.DataSources.Add(rds);
}
After loading the report stream (look at the code above), the GetDataSourceNames() method gives me all the DataSource (in effect DataSet if you look on the Report Data panel in the report designer) that is named inside the report.
So I named my DataSet as the DataTable from which I need to load my data, such as "V_REPORT_SCHOOLS", and then I loaded the DataTable by name from my DataSet.
Here is the main idea: You can have a mapping between your reports and your data table names and simply access data tables by name.
You can simply access to a data table in your DataSet by its name using Tables property:
datasetInstance.Tables["SchoolListDataTable"]
So it's enough to have a mapping between your reports and your data tables somewhere.
You can use settings or any thing else for this mapping. for example this mapping can be a simple key-value Dictionary<string,string> having your report name or whatever you have in your combobox as Key and your data table name as Value:
var mapping = new Dictionary<string, string>();
mapping.Add("report1", "table1");
mapping.Add("report2", "table2");
and then use selected value of combobox to retrieve required table name from that mapping dictionary:
//Find selected report
var reportSource = cmbReport.SelectedValue.ToString();
//Load report definition
Stream reportStream = assembly.GetManifestResourceStream(reportSource);
reportViewer1.LocalReport.LoadReportDefinition(reportStream);
//I supppose you use whatever you put in combobox, as mapping key
//Find the table name
var tableName = mapping[reportSource];
//Set report data source
ReportDataSource rds = new ReportDataSource("DataSetName", datasetInstance.Tables[tableName]);
Report doesn't store DataSet information
When you're creating your report, you select your DataSource so that the designer may collect metadata from it (Column names, data types, etc). It then pretty much forgets it except for the fact it creates a dataset file (.xsd).
From there when you're loading the report you need to initialize a ReportDataSource telling it where to get the data from, because the report itself (.rdlc file) does not store this information.
Think of it as a sort of separation of concerns to prevent coupling. I believe (not certain) it's so that you can have 2 table schemas that are identical in two different locations (Let's say Development environment and Production environment) and point it at either of them. Additionally I believe you can set reports to load from things other than databases, such as xml files if you desired which leads partially to another reason it is this way.
I'm writing an application which changes Crystal Reports database access parameters in report files. I open reports witin a .NET windows forms app and apply the SDK functionality to change driver type (ODBC/OLEDB), server name, database name, user, password, authentication type etc. I'm having a problem with the database name. My code DOES change the specific properties of the table ConnectionInfo (in subreports too) but fails to update the general SQL Query within the report. This results in the report still accessing the old database.
So if the original report was configured to access database_1 and I'm changing it to database_2, it will have all table properties properly changed to database_2 (verifiable in the Designer). It will still have database_1 in the query though. The database name remains unchanged in both the SDK RowsetController.GetSQLStatement() result and in the Crystal Reports Developer query view (Database->Show SQL Query...).
Also I have to have both databases (database_1 and database_2) online while the conversion takes place, otherwise I get exceptions on either GetSQLStatement(when database_1 is offline; becuase it still refers to it) or SetTableLocation (when database_2 is offline - this is expected and acceptable behavior though). If both db are online, there are no errors.
Here is exactly what I'm using:
1) CrystalDecisions.CrystalReports.Engine.ReportDocument.Load(filePath, OpenReportMethod.OpenReportByTempCopy)
(...)
2) Make and fill CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag
3) Iterate through CrystalDecisions.ReportAppServer.DataDefModel.Tables and apply all properties with SetTableLocaiton() for each one.
4) Repeat with each subreport
5) RowsetController.GetSQLStatement() to view the report's sql query.
Is there some way to update the query basing on the new table ConnectionInfos (which seem to be set properly)? I don't even see any possibility of manually updating the query (GET, search&replace, SET).
I'm using:
.NET 4.5,
Visual Studio 2012,
CR for VS 13.0.5,
Crystal Reports Developer 9.2.2.693 for results verification (source reports are also created with it)
Answer: set propper QualifiedName for each table. The QualifiedName is the full name of the table including the DbName. This later appears in the SQL Query of the report. By qualified name we understand:
myDatabase.mySchema.myTableName
Code example:
CrystalDecisions.ReportAppServer.DataDefModel.Table boTable = new CrystalDecisions.ReportAppServer.DataDefModel.Table();
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boMainPropertyBag = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag boInnerPropertyBag = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
// Custom function to fill property bags with values which influence the table properties as seen in CR Developer
FillPropertyBags(boMainPropertyBag, boInnerPropertyBag);
CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo boConnectionInfo = new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo();
boConnectionInfo.Attributes = boMainPropertyBag;
boConnectionInfo.Kind = CrystalDecisions.ReportAppServer.DataDefModel.CrConnectionInfoKindEnum.crConnectionInfoKindCRQE;
boTable.ConnectionInfo = boConnectionInfo;
CrystalDecisions.ReportAppServer.DataDefModel.Tables boTables = boReportDocument.ReportClientDocument.DatabaseController.Database.Tables;
for (int i = 0; i < boTables.Count; i++)
{
boTable.Name = boTables[i].Name;
// the QualifiedName is directly taken into the CR general query so this is a quick fix to change it
boTable.QualifiedName = boTables[i].QualifiedName.Replace("oldDbName", "newDbName");
boTable.Alias = boTables[i].Alias;
boReportDocument.ReportClientDocument.DatabaseController.SetTableLocation(boTables[i], boTable);
}
Uhh...Researching for whole day and found answer after publishing question on SO.
I've used reflection to extract the sql query being used by a Crystal Report. I then use this extracted sql (very carefully) to fill a dataset, which IO then bind to my ReportDocument object via the SetDataSource method. All this goes smoothly, but whenever I'm trying to view or export my report, it requires that I provide my credentials / parameter values, which defeats the purpose of querying/binding my data manually.
Is there any way around having to provide credentials / parameters when my report data is being push into the report (i.e. can I get the report to not refresh istself from the database directly?) I've tried setting the "save with data" value, but it doesn't seem to help.
May be it can help:
ReportDocument cryReportDocument = .......;
cryReportDocument.SetDatabaseLogon("userName", "password");
cryReportDocument.SetParameterValue("parameterName", value);
CrystalReportViewer1.ReportSource = cryReportDocument;