How to dynamically change crystal report database connection - c#

I am new with crystal reports. I tried to to implement the crystal report in my win form c# application using report wizard visual studio 2012, so don't know what happen's in backhand for this. Everything works good on my computer but when i tried install this on another computer connection string changes and gives error.
I tried many links like Dynamic Connection string Change but as i am using report wizard for setup so don't know where to use this.
I also tried all options in report wizard for connection string but didn't find anything that change connection string at run time.
Is there any options by which i can attach connection String from app config at run time.

Try something like this:
strServer= ConfigurationManager.AppSettings["ServerName"].ToString();
strDatabase= ConfigurationManager.AppSettings["DataBaseName"].ToString();
strUserID= ConfigurationManager.AppSettings["UserId"].ToString();
strPwd= ConfigurationManager.AppSettings["Password"].ToString();
report.DataSourceConnections[0].SetConnection(strServer, strDatabase, strUserID, strPwd);

strServer= ConfigurationManager.AppSettings["ServerName"].ToString();
strDatabase= ConfigurationManager.AppSettings["DataBaseName"].ToString();
strUserID= ConfigurationManager.AppSettings["UserId"].ToString();
strPwd= ConfigurationManager.AppSettings["Password"].ToString();
//may be you need to set the integrated security to false, first.
report.DataSourceConnections[o].IntegratedSecurity = False;
report.DataSourceConnections[0].SetConnection(strServer, strDatabase, strUserID, strPwd);

Here's an example of changing all the main report tables as well as all subreports tables, to a newly specified TargetServer and TargetDatabase with Integrated Authentication:
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
// using CrystalDecisions.ReportAppServer.CommLayer; // not used directly, but this is needed in Project References.
//
// be sure to set "copy local" = true in the Project:
// see https://stackoverflow.com/questions/38025601/could-not-load-file-or-assembly-crystaldecisions-reportappserver-commlayer-ver
static ReportDocument crReportDocument;
static ConnectionInfo crConnectionInfo = new ConnectionInfo();
static public string TargetServer { get; set; }
static public string TargetDatabase { get; set; }
static void crAssignConnectionInfo()
{
crConnectionInfo.UserID = "";
crConnectionInfo.Password = "";
crConnectionInfo.DatabaseName = TargetDatabase;
crConnectionInfo.ServerName = TargetServer;
crConnectionInfo.IntegratedSecurity = true; // in case the report was saved with SQL authentication, switch to Integrated
}
static void SetSubreportLoginInfo(CrystalDecisions.CrystalReports.Engine.Sections objSections)
{
foreach (Section section in objSections)
{
foreach (ReportObject reportObject in section.ReportObjects)
{
SubreportObject crSubreportObject;
switch (reportObject.Kind)
{
case ReportObjectKind.SubreportObject:
crSubreportObject = (SubreportObject)reportObject;
ReportDocument subRepDoc = crSubreportObject.OpenSubreport(crSubreportObject.SubreportName);
if (subRepDoc.ReportDefinition.Sections.Count > 0) {
SetSubreportLoginInfo(subRepDoc.ReportDefinition.Sections);
}
Tables crTables = subRepDoc.Database.Tables;
foreach (Table table in crTables)
{
TableLogOnInfo tableLogOnInfo = new TableLogOnInfo();
tableLogOnInfo.ConnectionInfo.UserID = crConnectionInfo.UserID;
tableLogOnInfo.ConnectionInfo.Password = crConnectionInfo.Password;
tableLogOnInfo.ConnectionInfo.DatabaseName = crConnectionInfo.DatabaseName;
tableLogOnInfo.ConnectionInfo.ServerName = crConnectionInfo.ServerName;
tableLogOnInfo.ConnectionInfo.IntegratedSecurity = crConnectionInfo.IntegratedSecurity;
table.ApplyLogOnInfo(tableLogOnInfo);
}
break;
case ReportObjectKind.FieldObject:
case ReportObjectKind.TextObject:
case ReportObjectKind.LineObject:
case ReportObjectKind.BoxObject:
case ReportObjectKind.PictureObject:
case ReportObjectKind.ChartObject:
case ReportObjectKind.CrossTabObject:
case ReportObjectKind.BlobFieldObject:
case ReportObjectKind.MapObject:
case ReportObjectKind.OlapGridObject:
case ReportObjectKind.FieldHeadingObject:
case ReportObjectKind.FlashObject:
default:
// none of the other objects need to have login assigned
break;
}
}
}
}
static void SetCrystalDocumentLogon()
{
crAssignConnectionInfo();
TableLogOnInfo crTableLogonInfo = new TableLogOnInfo();
foreach (Table crTable in crReportDocument.Database.Tables)
{
try
{
crConnectionInfo.Type = crTable.LogOnInfo.ConnectionInfo.Type;
crTableLogonInfo.ConnectionInfo = crConnectionInfo;
crTableLogonInfo.ReportName = crTable.LogOnInfo.ReportName;
crTableLogonInfo.TableName = crTable.LogOnInfo.TableName;
crTable.ApplyLogOnInfo(crTableLogonInfo);
}
catch (Exception ex)
{
Console.WriteLine("Error during SetCrystalDocumentLogon " + ex.Message);
throw;
}
SetSubreportLoginInfo(crReportDocument.ReportDefinition.Sections);
}
}

Related

crystal report with sub reports not working on production/test machine C# winforms

I have created crystal report with 8 sub-reports (using VS 2010). I have created stored proc which populates all the dump SQL server tables which are linked to main report & sub reports. My code is working fine on development machine but when same is deployed to another machine it throws following error.
Failed to Open the connection.
Details : [Database vendor code 17]
Failed to Open the connection.
rpt_reportName{GUID}.rpt
Details : [Database vendor code 17]
following is my code to generate report.
ReportDocument crReportDocument;
Boolean TypesDSReports = false;
clsErrorLog oLog = new clsErrorLog();
static TableLogOnInfo crTableLogonInfo;
static ConnectionInfo crConnectionInfo;
static Tables crTables;
static Database crDatabase;
public static void ReportLogin(ReportDocument crDoc, string Server, string Database, string UserID, string Password)
{
crConnectionInfo = new ConnectionInfo();
crConnectionInfo.ServerName = Server;
crConnectionInfo.DatabaseName = Database;
crConnectionInfo.UserID = UserID;
crConnectionInfo.Password = Password;
crDatabase = crDoc.Database;
crTables = crDatabase.Tables;
foreach (CrystalDecisions.CrystalReports.Engine.Table crTable in crTables)
{
crTableLogonInfo = crTable.LogOnInfo;
crTableLogonInfo.ConnectionInfo = crConnectionInfo;
crTable.ApplyLogOnInfo(crTableLogonInfo);
}
//crDoc.Subreports["aa"].co = crConnectionInfo;
}
private void DisplayReportWithSubReport()
{
try
{
ReportDocument crReportDocument = new ReportDocument();
crReportDocument.Load(sReportPath.Trim());
ReportLogin(crReportDocument, clsCustomize.gsPropServerName, clsCustomize.gsPropCurrentDataBaseName, clsCustomize.gsPropDataBaseUserID, clsCustomize.gsPropDataBasePassword);
crReportDocument.Refresh();
CRViewer.ReportSource = crReportDocument;
CRViewer.RefreshReport();
this.Text = sDisplayReportCaption;
if (TypesDSReports == false)
{
crReportDocument.PrintOptions.PaperSize = CrystalDecisions.Shared.PaperSize.PaperA4;
}
this.WindowState = FormWindowState.Maximized;
if (HMS.Common.clsConstants.gbPropCloseReportForm == true)
{
crReportDocument.PrintOptions.PaperSize = CrystalDecisions.Shared.PaperSize.PaperA4;
if (HMS.clsCustomize.giNoOfPrintCopies == 0)
{
HMS.clsCustomize.giNoOfPrintCopies = 1;
}
crReportDocument.PrintToPrinter(HMS.clsCustomize.giNoOfPrintCopies, false, 1, 1);
HMS.Common.clsConstants.gbPropCloseReportForm = false; //Reset the Flag
this.Close();
}
else
{
this.WindowState = FormWindowState.Maximized;
}
}
catch (Exception ex)
{
oLog.LogError(ex, "", "", "", "");
}
}
Dev machine and target machine both have same system configuration.Kindly help where is the issue?
Regards,
Vikram
I'm not 100% on this but I'm pretty sure that it's not enough to set the connection info at the top level only. You need to loop through your subreports / tables and apply the logonInfo to each
crDoc.Subreports[x].Database.Tables[y].ApplyLogOnInfo(crTableLogonInfo) ...
I figured out solution myself. I added following code in the ReportLogin method and it worked perfectly.
for (int i = 0; i < crDoc.Subreports.Count; i++)
{
crDoc.Subreports[i].SetDatabaseLogon(UserID, Password, Server, Database);
}

Create crystal report at runtime using a remote sql server as data source

I had my database and applications (web, api & service bus that all create crystal reports at runtime) on the same server. All worked perfect creating reports at runtime.
Moved the database to a different server, which only allow remote connections from the app server.
For my database connections, all I had to do in my projects was change the server in the connection string from (local) to the ip address of the database server, and it all works fine.
However it seems that to just change the server from (local) to the ip address for the crystal reports does not work (give a "Database logon failed" error)
I'm not sure if this is the problem, but for creating the report locally (before uploading the .rpt to the server) I had to create a connection where the server is set to "local" ( in the data source location). Since I cannot access the new database remotely from my local machine, I cannot change that)
The code I use look as follow:
string server = ConfigurationManager.AppSettings["Server"];
string database = ConfigurationManager.AppSettings["Database"];
string user = ConfigurationManager.AppSettings["DatabaseUser"];
string password = ConfigurationManager.AppSettings["DatabasePassword"];
var report = new ReportClass {FileName = reportPath};
report.Load();
report.SetDatabaseLogon(user, password, server, database);
var parameterValue = new ParameterDiscreteValue {Value = item.Id};
var parameter = new ParameterValues {parameterValue};
report.DataDefinition.ParameterFields["#id"].ApplyCurrentValues(parameter);
report.ExportToDisk(ExportFormatType.PortableDocFormat, path);
Thank you, I ended up with this that worked (using sql)
Essentially the idea is setting the logon info not just for the report, but also for all subreports. Would have been nice if one could just do a "foreach subreport in report.." ,but seems not to work that way
public static void SetConnections(ReportDocument report)
{
Database database = report.Database;
Tables tables = database.Tables;
var crConnInfo = new ConnectionInfo
{
ServerName = ConfigurationManager.AppSettings["Server"],
DatabaseName = ConfigurationManager.AppSettings["Database"],
UserID = ConfigurationManager.AppSettings["DatabaseUser"],
Password = ConfigurationManager.AppSettings["DatabasePassword"]
};
foreach (Table table in tables)
{
TableLogOnInfo crLogOnInfo = table.LogOnInfo;
crLogOnInfo.ConnectionInfo = crConnInfo;
table.ApplyLogOnInfo(crLogOnInfo);
}
Sections crSections = report.ReportDefinition.Sections;
foreach (Section crSection in crSections)
{
ReportObjects crReportObjects = crSection.ReportObjects;
foreach (ReportObject crReportObject in crReportObjects)
{
if (crReportObject.Kind == ReportObjectKind.SubreportObject)
{
var crSubreportObject = (SubreportObject)crReportObject;
ReportDocument subRepDoc = crSubreportObject.OpenSubreport(crSubreportObject.SubreportName);
Database crDatabase = subRepDoc.Database;
Tables crTables = crDatabase.Tables;
foreach (Table crTable in crTables)
{
TableLogOnInfo crLogOnInfo = crTable.LogOnInfo;
crLogOnInfo.ConnectionInfo = crConnInfo;
crTable.ApplyLogOnInfo(crLogOnInfo);
}
}
}
}
}
I use Crystal report on oracle database, in my application i use this code:
CrystalDecisions.CrystalReports.Engine.ReportDocument rpt = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
//reset connection
DBController.LogonEx(DBAlias, "", DBUsername, DBPassword);
//Create the QE (query engine) propertybag with the provider details and logon property bag
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag QE_Details = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
ConnectionInfo ci = DBController.GetConnectionInfos(null)[0];
//copy from existing attributes except for server name
for (int idx = 0; idx < ci.Attributes.PropertyIDs.Count; idx++)
{
switch (ci.Attributes.PropertyIDs[idx])
{
case "QE_ServerDescription":
QE_Details.Add(ci.Attributes.PropertyIDs[idx], DBAlias);
break;
case "QE_LogonProperties":
//this is itself a property bag
CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag logonDetails = new CrystalDecisions.ReportAppServer.DataDefModel.PropertyBag();
PropertyBag OLDLogon = (PropertyBag)ci.Attributes[ci.Attributes.PropertyIDs[idx]];
for (int idx2 = 0; idx2 < OLDLogon.PropertyIDs.Count; idx2++)
{
switch (OLDLogon.PropertyIDs[idx2])
{
case "Server":
case "Data Source":
logonDetails.Add(OLDLogon.PropertyIDs[idx2], DBAlias);
break;
default:
logonDetails.Add(OLDLogon.PropertyIDs[idx2], OLDLogon[OLDLogon.PropertyIDs[idx2]]);
break;
}
}
QE_Details.Add(ci.Attributes.PropertyIDs[idx], logonDetails);
break;
default:
QE_Details.Add(ci.Attributes.PropertyIDs[idx], ci.Attributes[ci.Attributes.PropertyIDs[idx]]);
break;
}
}
//now replace all existing connections with new one
CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo newConnInfo = new CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo();
newConnInfo.Attributes = QE_Details;
newConnInfo.Kind = CrystalDecisions.ReportAppServer.DataDefModel.CrConnectionInfoKindEnum.crConnectionInfoKindCRQE;
newConnInfo.UserName = DBUsername;
newConnInfo.Password = DBPassword;
foreach (CrystalDecisions.ReportAppServer.DataDefModel.ConnectionInfo oldConnInfo in DBController.GetConnectionInfos(null))
{
DBController.ReplaceConnection(oldConnInfo, newConnInfo.Clone(true), null, CrystalDecisions.ReportAppServer.DataDefModel.CrDBOptionsEnum.crDBOptionDoNotVerifyDB);
}
i hope this help

Changing a Crystal Report datasource (access) at runtime in C#

I'm getting the error 'Log on failed' when trying to change my datasource at runtime. I've trawled SO and the SAP site and from that put together the code below, but I'm still getting the error. My access db is 2013 and isn't password protected and I'm using the default "Admin" user. The report has an OLE DB connection. My code loops through all tables, including subreports and changes the login, and I also change the database login. Any help much appreciated:
public void RunTestReport()
{
DataSet testDataSet = new DL.NonConformance().GetNonConformances(1, "NonConformance");
var rpt = new ReportDocument();
rpt.Load(#"C:\Reports\rptTest.rpt");
SetCrystalLogin(rpt);
rpt.SetDataSource(testDataSet);
crystalReportViewer1.ReportSource = rpt;
crystalReportViewer1.Refresh();
}
public void SetCrystalLogin(ReportDocument oRpt)
{
ConnectionInfo oConnectInfo = new ConnectionInfo();
string dbpath = string.Concat(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), #"\db\dbacc.db");
oConnectInfo.ServerName = dbpath;
oConnectInfo.DatabaseName = string.Empty;
oConnectInfo.UserID = "Admin";
oConnectInfo.Password = string.Empty;
// Set the logon credentials for all tables
SetCrystalTablesLogin(oConnectInfo, oRpt.Database.Tables);
// Check for subreports
foreach (CrystalDecisions.CrystalReports.Engine.Section oSection in oRpt.ReportDefinition.Sections)
{
foreach (CrystalDecisions.CrystalReports.Engine.ReportObject oRptObj in oSection.ReportObjects)
{
if (oRptObj.Kind == CrystalDecisions.Shared.ReportObjectKind.SubreportObject)
{
// This is a subreport so set the logon credentials for this report's tables
CrystalDecisions.CrystalReports.Engine.SubreportObject oSubRptObj = oRptObj as CrystalDecisions.CrystalReports.Engine.SubreportObject;
// Open the subreport
CrystalDecisions.CrystalReports.Engine.ReportDocument oSubRpt = oSubRptObj.OpenSubreport(oSubRptObj.SubreportName);
SetCrystalTablesLogin(oConnectInfo, oSubRpt.Database.Tables);
}
}
}
oRpt.Refresh();
oRpt.SetDatabaseLogon("Admin", string.Empty, dbpath, string.Empty, true);
oRpt.VerifyDatabase();
oRpt.Refresh();
}
private void SetCrystalTablesLogin(CrystalDecisions.Shared.ConnectionInfo oConnectInfo, Tables oTables)
{
foreach (CrystalDecisions.CrystalReports.Engine.Table oTable in oTables)
{
CrystalDecisions.Shared.TableLogOnInfo oLogonInfo = oTable.LogOnInfo;
oLogonInfo.ConnectionInfo = oConnectInfo;
oTable.ApplyLogOnInfo(oLogonInfo);
}
}
Turns out you can't configure a .accdb datasource at runtime, I'll need to create an ODBC connection.

Crystal Report Connection string from properties.settings winform c#

Is it possible to set the connection string of crystal report from the properties.settings of a winform in c# like the following?
this is just my assumptions
rpt.connectionString = Properties.Settings.Default.ConnectionString
This is my code for managing logins/connectionstrings (dbLogin is just a simple class for storing information, you can replace that with string values).
//Somewhere in my code:
foreach (CrystalDecisions.CrystalReports.Engine.Table tbCurrent in rdCurrent.Database.Tables)
SetTableLogin(tbCurrent);
//My set login method
private void SetTableLogin(CrystalDecisions.CrystalReports.Engine.Table table)
{
CrystalDecisions.Shared.TableLogOnInfo tliCurrent = table.LogOnInfo;
tliCurrent.ConnectionInfo.UserID = dbLogin.Username;
tliCurrent.ConnectionInfo.Password = dbLogin.Password;
if(dbLogin.Database != null)
tliCurrent.ConnectionInfo.DatabaseName = dbLogin.Database; //Database is not needed for Oracle & MS Access
if(dbLogin.Server != null)
tliCurrent.ConnectionInfo.ServerName = dbLogin.Server;
table.ApplyLogOnInfo(tliCurrent);
}
In case you already have a successfull connectiont to SQL Server, you may use the following static method to set your report connection based on your SqlConnection:
using System.Text;
using CrystalDecisions.Shared;
using System.Data.SqlClient;
namespace StackOverflow
{
public class MyCrystalReports
{
// This method will allow you may easily set report datasource based on your current SqlServerConnetion
public static void SetSqlConnection(CrystalDecisions.CrystalReports.Engine.ReportClass MyReport, SqlConnection MySqlConnection)
{
// You may even test SqlConnection before using it.
SqlConnectionStringBuilder SqlConnectionStringBuilder = new SqlConnectionStringBuilder(MySqlConnection.ConnectionString);
string ServerName = SqlConnectionStringBuilder.DataSource;
string DatabaseName = SqlConnectionStringBuilder.InitialCatalog;
Boolean IntegratedSecurity = SqlConnectionStringBuilder.IntegratedSecurity;
string UserID = SqlConnectionStringBuilder.UserID;
string Password = SqlConnectionStringBuilder.Password;
// Of course, you may add extra settings here :D
// On Crystal Reports, connection must be set individually for each table defined on the report document
foreach (CrystalDecisions.CrystalReports.Engine.Table Table in MyReport.Database.Tables)
{
CrystalDecisions.Shared.TableLogOnInfo TableLogOnInfo = Table.LogOnInfo;
TableLogOnInfo.ConnectionInfo.ServerName = ServerName;
TableLogOnInfo.ConnectionInfo.DatabaseName = DatabaseName;
TableLogOnInfo.ConnectionInfo.IntegratedSecurity = IntegratedSecurity;
if (IntegratedSecurity != true)
{
TableLogOnInfo.ConnectionInfo.UserID = UserID;
TableLogOnInfo.ConnectionInfo.Password = Password;
}
Table.ApplyLogOnInfo(TableLogOnInfo);
}
}
}
}

Crystal report datsource Set by ConnectionInfo is not getting set- Does not connect to right database

I have 8 reports that use the exact same code to set the reporting datasource out of which 5 reports work and are able to point to Production environment. The rest of the 3 reports, I have ran and rerun database verify and database update yet when I run these reports on production, they bring data back from DEV environment.
Here is how my datasource is getting set.
I call stored procedure in all 8 crystal reports .
I have done very detailed debugging and verified that the datasource data is getting the correct information so what is missing.
string database = ConfigurationManager.AppSettings[env + "Database"].ToString();
string server = ConfigurationManager.AppSettings[env + "Server"].ToString();
CrystalReportViewer1.ParameterFieldInfo = fields;
rptDoc.Load(Server.MapPath(report));
ConnectionInfo connectionInfo = Reports.GetConnectionInfo(server, database, "userID", "password");
//connectionInfo.Attributes = attributes;
connectionInfo.Type = ConnectionInfoType.SQL;
SetDBLogonForReport(connectionInfo, env);
CrystalReportViewer1.ReportSource = rptDoc;
private void SetDBLogonForReport(ConnectionInfo oConnectionInfo, string env)
{
try
{
TableLogOnInfos oTableLogOnInfos = CrystalReportViewer1.LogOnInfo;
string[] sparams = new string[]{
};
foreach (CrystalDecisions.CrystalReports.Engine.Table oTable in rptDoc.Database.Tables)
{
if (oTable.LogOnInfo.ConnectionInfo.ServerName == oConnectionInfo.ServerName)
{
TableLogOnInfo oTableLogOnInfo = oTable.LogOnInfo;
oTableLogOnInfo.ConnectionInfo = oConnectionInfo;
oTable.ApplyLogOnInfo(oTableLogOnInfo);
// oTable.Location = String.Format( "{0}.dbo.{1}", oConnectionInfo.DatabaseName, oTable.Name );
bool b = oTable.TestConnectivity();
if (!b)
{
invokeErrorLogger(sparams, env);
}
}
}
}
catch
{
throw;
}
}
The reports that work are already pointing to your prod server. You are only applying the logon credentials if the server stored in the report matches the server name you are trying to set. Change to the following:
// Clear existing connection info first
rptDoc.DataSourceConnections.Clear();
foreach (CrystalDecisions.CrystalReports.Engine.Table oTable in rptDoc.Database.Tables)
{
var oTableLogonInfo = oTable.LogonInfo;
oTableLogonInfo.ConnectionInfo = oConnectionInfo;
oTable.ApplyLogOnInfo(oTableLogonInfo);
bool b = oTable.TestConnectivity();
if (!b)
{
invokeErrorLogger(sparams, env);
}
}

Categories