Showing posts with label Crystal Reports. Show all posts
Showing posts with label Crystal Reports. Show all posts

Wednesday 20 May 2015

Conflict in log4net on GAC when a Crystal Report is viewed through .Net Code

We faced an issue sometime ago, which put us into a very tight situation. The issue was when a Crystal Report file is loaded through .Net code it threw the following error. This is the first of a series of error which lead to another and so forth.

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.TypeInitializationException: The type initializer for 'CrystalDecisions.ReportSource.ReportSourceFactory' threw an exception.
---> System.TypeInitializationException: The type initializer for 'CrystalDecisions.Shared.SharedUtils' threw an exception.
---> System.IO.FileLoadException: Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral,
PublicKeyToken=692fbea5521e1304' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.
(Exception from HRESULT: 0x80131040)
File name: 'log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=692fbea5521e1304'
   at CrystalDecisions.Shared.SharedUtils..cctor()

 

And the confusion grew even further when we checked the GAC (Global Assembly Cache). Because we could see that in GAC, the mentioned assembly (log4net) is being registered with the version 1.2.10.0 and with the correct ‘PublicKeyToken’ (692fbea5521e1304).

image

And we didn’t really worry about the ‘Processor Architecture’ column, since our development environment is 64-bit and all the Crystal Reports development pre-requisites were there in the development environment and Crystal Runtime was already installed (version 13 – 64-bit). And in our application code we were using the same log4net and it was already presented in the bin folder.

Then when we googled the issue we could be able to come across with similar incidents, where the majority of the people were able to resolve the issue by installing the Crystal Runtime. But it was sort of a puzzle to us since we already had it installed it. But later we tried by un-installing the runtime and re-installing it again, assuming some corruption might had occur during the previous installation or afterwards. But the result was same.

Then we came across with the following article which gave us some kind of a hint of the issue we are facing:

http://scn.sap.com/message/9848374#9848374

And it occurred to us that even though we had the same assembly which the error is pointing installed in GAC, still the Crystal assemblies were expecting some other log4net assembly to be presented in GAC.

Therefore we installed the Crystal Runtime version 13 for 32-bit. Afterwards the GAC was having both the assemblies registered.

image

And this resolved the issue. And we came to a conclusion that even our development environment is 64-Bit, we need to have the log4net assembly for 32-bit since crystal is referring to that internally.

Hope this would help you if you are facing the same problem.

Tuesday 9 August 2011

Change the data source of a Crystal Report at Run-time using C#

It’s a known fact, that in Crystal Reports, if you try to display details, using data in a SQL Server Database other than the one that you’ve used to design the report, either you have to set the database location (or refresh the report). This is a common issue that development team face when the reports are being deployed to the production environment.

But this can be prevented using the following method.

Following namespaces are required.

using CrystalDecisions.CrystalReports.Engine;

using CrystalDecisions.Shared;



And we have to assign the required SQL server information to each table/view of the report, sub reports and the report viewer.

Use the following code:


SQLReport report = new SQLReport();

//Get SQL Server Details
string zServer = @"SERVER_NAME";
string zDatabase = @"DATABASE";
string zUsername = @"USER";
string zPassword = @"PASSWORD";

ConnectionInfo ciReportConnection = new ConnectionInfo();

ciReportConnection.ServerName = zServer;
ciReportConnection.DatabaseName = zDatabase;
ciReportConnection.UserID = zUsername;
ciReportConnection.Password = zPassword;

//Assign data source details to tables

foreach (Table table in report.Database.Tables) {
table.LogOnInfo.ConnectionInfo = ciReportConnection;
table.ApplyLogOnInfo(table.LogOnInfo);
}

foreach (ReportDocument subrep in report.Subreports) {
foreach (Table table in subrep.Database.Tables) {
table.LogOnInfo.ConnectionInfo = ciReportConnection;
table.ApplyLogOnInfo(table.LogOnInfo);
}
}

//Assign data source details to the report viewer
if (this.crystalReportViewer1.LogOnInfo != null) {
TableLogOnInfos tlInfo = this.crystalReportViewer1.LogOnInfo;
foreach (TableLogOnInfo tbloginfo in tlInfo) {
tbloginfo.ConnectionInfo = ciReportConnection;
}
}


crystalReportViewer1.ReportSource = report;
crystalReportViewer1.Refresh();

Monday 8 August 2011

Invoke a custom method when Crystal Report Viewers’ print button is clicked / Add custom button to Crystal Report Viewer Toolbar

If you are developing applications which includes reporting with Crystal Reports, you may have noticed that it’s not possible to invoke a custom method, when the user prints the report. However this was something which was easily implemented in Crystal Reports 8/8.5 but removed from latter versions.

But there’s a workaround for this. In this example I will show you how to invoke a method in our client application, when the print button of the report viewer is clicked.

In order to do that we have to add our custom method to the report viewers’ print buttons’ print action.

Create a new windows application.

Add another form to the project and name it as ‘CustomReportViewer.cs’.

Add a Crystal Report viewer to a newly created form. (If the crystal report viewer is not available in the toolbox, please add it to the toolbox first)

img_scr_001_a

img_scr_002

Add new report to the project and name it as ‘SampleReport.rpt’.

img_scr_003

Now add the following code to the ‘CustomReportViewer’ class

public delegate void CustomPrintDelegate();


Add the following property.


public Delegate CustomPrintMethod { get; set; }


Add this additional code to the initialization method.


foreach (Control control in crystalReportViewer1.Controls) {
if (control is System.Windows.Forms.ToolStrip) {

//Default Print Button
ToolStripItem tsItem = ((ToolStrip)control).Items[1];
tsItem.Click += new EventHandler(tsItem_Click);

//Custom Button
ToolStripItem tsNewItem = ((ToolStrip)control).Items.Add("");
tsNewItem.ToolTipText = "Custom Print Button";
tsNewItem.Image = Resources.CustomButton;
tsNewItem.Tag = "99";
((ToolStrip)control).Items.Insert(0, tsNewItem);
tsNewItem.Click += new EventHandler(tsNewItem_Click);
}
}


Using the above coding we can find out the print button of the report viewers’ too strip. And the 1st item is for the print button. (I have found this out from its ToolTipText).


How ever you can add your own button if you like or you can use the existing print button. Both options are illustrated.


Add the following methods.



void tsNewItem_Click(object sender, EventArgs e) {
if (CustomPrintMethod != null) {
CustomPrintMethod.DynamicInvoke(null);
}
}

void tsItem_Click(object sender, EventArgs e) {
if (CustomPrintMethod != null) {
CustomPrintMethod.DynamicInvoke(null);
}
}


Here is the complete coding of the ‘CustomReportViewer’ class.


using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;

namespace PrintDelegateMethod {
public partial class CustomReportViewer : Form {

public delegate void CustomPrintDelegate();

public Delegate CustomPrintMethod { get; set; }

public CustomReportViewer() {
InitializeComponent();

foreach (Control control in crystalReportViewer1.Controls) {
if (control is System.Windows.Forms.ToolStrip) {

//Default Print Button
ToolStripItem tsItem = ((ToolStrip)control).Items[1];
tsItem.Click += new EventHandler(tsItem_Click);

//Custom Button
ToolStripItem tsNewItem = ((ToolStrip)control).Items.Add("");
tsNewItem.ToolTipText = "Custom Print Button";
tsNewItem.Image = Resources.CustomButton;
tsNewItem.Tag = "99";
((ToolStrip)control).Items.Insert(0, tsNewItem);
tsNewItem.Click += new EventHandler(tsNewItem_Click);
}
}
}

void tsNewItem_Click(object sender, EventArgs e) {
if (CustomPrintMethod != null) {
CustomPrintMethod.DynamicInvoke(null);
}
}

void tsItem_Click(object sender, EventArgs e) {
if (CustomPrintMethod != null) {
CustomPrintMethod.DynamicInvoke(null);
}
}

private void CustomReportViewer_Load(object sender, EventArgs e) {
SampleReport report = new SampleReport();
crystalReportViewer1.ReportSource = report;
crystalReportViewer1.Refresh();
}
}
}


 


Add the following delegate to your calling class


public delegate void PrintDelegate();


Add the following method. This is the method that we want to invoke when the print button or the custom button is clicked.


private void CustomPrintMethod() {
MessageBox.Show("Custom Print Method");
}


And a button and the following click event code.


private void button1_Click(object sender, EventArgs e) {
CustomReportViewer viewer = new CustomReportViewer();
PrintDelegate mymethod = new PrintDelegate(CustomPrintMethod);
viewer.CustomPrintMethod = mymethod;
viewer.Show();

}


The complete source of the calling form:


using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace PrintDelegateMethod {
public partial class Form1 : Form {
public delegate void PrintDelegate();

public Form1() {
InitializeComponent();

}

private void CustomPrintMethod() {
MessageBox.Show("Custom Print Method");
}


private void button1_Click(object sender, EventArgs e) {
CustomReportViewer viewer = new CustomReportViewer();
PrintDelegate mymethod = new PrintDelegate(CustomPrintMethod);
viewer.CustomPrintMethod = mymethod;
viewer.Show();

}


}
}


Now if you run the project, you can get a similar screen shown below. And please note that I have added a resource file named ‘Resources’ and added an image named ‘CustomButton’

img_scr_011_a

And if you click either of the buttons, your custom method will be invoked. The default print method will be executed only when the print button is clicked.

img_scr_012

Wednesday 15 July 2009

The type initializer for 'crystaldecisions.crystalreports.engine.reportdocument' threw an exception - Resolved

Today I got this error, when I tried to deploy an application developed using Visual Studio 2005 and Crystal Reports 10.

I googled the problem and found out many solutions which worked for many people. But only one solution worked for me. Anyway I will post all the things that I have tried.


Solution #1

Run ‘CRRedist2005_x86.msi’. This file can be found on ‘C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\CrystalReports’. And if you have already installed this you will be prompted to Repair or Uninstall. But none is required if it’s already installed.

Solution #2

Uninstall the Crystal Reports for Visual Studio 2005 using the Visual Studio Instalation DVD and Reinstall it again.

Steps to uninstall the Crystal Reports for Visual Studio 2005

  1. Insert the Setup DVD

  2. Select ‘Change or Remove Visual Studio 2005’ (Then the setup will run on Maintenance Mode)

  3. Select ‘Add or Remove Features’

  4. Uncheck the ‘Crystal Reports For Visual Studio’ checkbox

  5. Click on ‘Update’ button

  6. Afterwards do the above steps and on step 4 select the ‘Crystal Reports For Visual Studio’ checkbox and click on ‘Update’ button


Solution #3

Create a setup using the Crystal Reports Merge Module, It can be downloaded from http://support.businessobjects.com/downloads/merge_modules.asp. And run it on the deployment machine


Solution #3 worked for me..

Hope this will be helpful to you …………