Crystal Reports – setting login credentials through code

I just answered a stackoverflow question regarding a common issue when using Crystal Reports as part of a wider application – setting login credentials through code. Its not as straight forward as it really ought to be.

Rather than simply setting the login/server/database details through a single call there are a number of things that are required:

First you setup a ConnectionInfo instance. In the example below I’m assuming that you already have a connection string instance in cnString:

var cn = new SqlConnectionStringBuilder(cnString)
var ci = ConnectionInfo() {
    Type = ConnectionInfoType.SQL,
    ServerName = cn.DataSource,
    IntegratedSecurity = cn.IntegratedSecurity,
    UserID = cn.UserID,
    Password = cn.Password,
    DatabaseName = cn.InitialCatalog};
Dim cn As New SqlConnectionStringBuilder(cnString)
Dim ci As New ConnectionInfo() With {
    .Type = ConnectionInfoType.SQL, _
    .ServerName = cn.DataSource, _
    .IntegratedSecurity = cn.IntegratedSecurity, _
    .UserID = cn.UserID, _
    .Password = cn.Password, _
    .DatabaseName = cn.InitialCatalog}

Next you need to apply this connection info throughout your report. I have found that its necessary to do this on every database table, for both your main report and also all sub reports. To make this easy, I used a recursive method to do all the looping and assigning:

void SetConnection(ReportDocument rd, crConnectionInfo ci)
{

    foreach (CrystalDecisions.CrystalReports.Engine.Table tbl in rd.Database.Tables)
    {
        TableLogOnInfo logon = tbl.LogOnInfo;
        logon.ConnectionInfo = ci;
        tbl.ApplyLogOnInfo(logon);
        tbl.Location = tbl.Location;
    }
    if (!rd.IsSubReport) {
        foreach {ReportDocument sd in rd.SubReports) {
            SetConnection(sd,ci)
        }
    }
}
Public Sub SetConnection(ByVal rd As ReportDocument, ByVal ci As crConnectionInfo)

    For Each tbl As CrystalDecisions.CrystalReports.Engine.Table In rd.Database.Tables
        Dim logon As TableLogOnInfo = tbl.LogOnInfo
        logon.ConnectionInfo = ci
        tbl.ApplyLogOnInfo(logon)
        tbl.Location = tbl.Location
    Next

    If Not rd.IsSubReport Then
        For Each sd As ReportDocument in rd.SubReport
            SetConnection(sd,ci)
        Next
    End If

End Sub

Notes:

  • This method never needs to call SetDatabaseLogon on the `ReportDocument class
  • The call that setstbl.Location to itself is intended. In the version I was using it didn’t work without this initialization (I assume there’s some code in their property setter).

Caveat: I’ve hand coded all the above code, and don’t have a means to test it out. If you find typos or other issues with it, let me know in the comments I’ll make amendments.

Leave a Reply

Your email address will not be published.

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

This site uses Akismet to reduce spam. Learn how your comment data is processed.