Link to home
Start Free TrialLog in
Avatar of WalterRautenbach
WalterRautenbach

asked on

Load report failed

Hello,

I am receiving a "Load report failed" error when i try viewing reports on my website that contains embedded Crystal reports. When i begun receiving these errors, cleared out the temp folder "C:\WINDOWS\Temp", assigned modify, read write rights to IIS/WPG, set  impersonate="false" in my web config file, and it still didn't help and my code also caters for closing and disposing the report and utilizes the garbage collector. So i restarted IIS, which did do the trick, but is there any other way of prevent this error from occuring again, instead of restarting IIS, since my website utilizes sessions, and session values will be lost.
public ReportDocument myReport;
protected void Page_Unload(object sender, EventArgs e)
{
        if (myReport!= null)
        {
            myReport.Close();
            myReport.Dispose();
        }
        GC.Collect(); 
}

Open in new window

Avatar of RiteshShah
RiteshShah
Flag of India image

that is because you have reached maximum limit of report. You can use following code for that. for further explanation, have a look at following links

http://www.crystalreportsbook.com/Forum/forum_posts.asp?TID=1205

public class ReportFactory
{
      public static Hashtable reportTable = new Hashtable();
     
      public static void CreateReport(string key, string path)
      {
            ReportDocument report = new ReportDocument();
            report.Load(path);
            reportTable.Add(key, report);
      }
  
      public static void CloseReport(string key)
      {
            ((ReportDocument)reportTable[key]).Close();
            ((ReportDocument)reportTable[key]).Dispose();
            reportTable.Remove(key);
      }
}
 

Open in new window

Avatar of WalterRautenbach
WalterRautenbach

ASKER

Thank you for the comment, what does the "key" reference, i understand the "path" is the path of the .rpt file.
actually that was not a good and full example, let me give you class code which I am using in my production. You can generate one class file for this and use it.



using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using CrystalDecisions.CrystalReports.Engine;
using System.IO;
using System.Text;
using System.Web.Caching;
using System.Diagnostics;
 
/// <summary>
/// Summary description for ReportDocumentFactory
/// </summary>
public class ReportDocumentFactory
{
 
	//Crystal printJobLimit key is in registry:
	//HKEY_LOCAL_MACHINE\SOFTWARE\Crystal Decisions\10.2\Report Application Server\Server\PrintJobLimit
	const int CRYSTAL_PRINT_JOB_LIMIT = 75; //default value is 75, it must by sincronized with registry!
 
	const string REPORT_DOCUMENT_CAHE_KEY = "ReportDocumentQueue";
 
	private Dictionary<string, ReportDocumentInfo> docList;
 
 
	public ReportDocumentFactory(Cache cache)
	{
		try
		{
			docList = (Dictionary<string, ReportDocumentInfo>)cache[REPORT_DOCUMENT_CAHE_KEY];
		}
		catch (InvalidCastException ex)
		{
			//if generic dictionary is compiled dinamically, we must clean report cache.
			//This has a problem, because the processed reports are not disposed, this case
			//should not happen to.
			cache.Remove(REPORT_DOCUMENT_CAHE_KEY);
			docList = null;
		}
 
		if (docList == null)
		{
			docList = new Dictionary<string, ReportDocumentInfo>(CRYSTAL_PRINT_JOB_LIMIT);
 
			cache.Add(REPORT_DOCUMENT_CAHE_KEY, docList, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 20, 0),
				CacheItemPriority.AboveNormal, new CacheItemRemovedCallback(this.CacheRemovedCallback));
		}
	}
 
	public string Add(ReportDocument reportDoc)
	{
		Debug.WriteLine("Add() called.");
 
		if (docList.Count + 1 >= CRYSTAL_PRINT_JOB_LIMIT)
		{
			Debug.WriteLine("Add() CRYSTAL_PRINT_JOB_LIMIT Reached.");
 
			try
			{
				//dequeue de old one (FIFO)
				List<ReportDocumentInfo> rInfoSortList = new List<ReportDocumentInfo>(docList.Values);
 
				rInfoSortList.Sort(delegate(ReportDocumentInfo rInfo1, ReportDocumentInfo rInfo2)
									{
										return DateTime.Compare(rInfo1.Date, rInfo2.Date);
									});
 
				Remove(rInfoSortList[0].Key);
			}
			catch (Exception e)
			{
				//TODO: log
				Debug.WriteLine("Add() error: " + e.Message);
 
				try
				{
					Remove(docList.Keys.GetEnumerator().Current.ToString());
				}
				catch { }
			}
		}
 
		string key = Guid.NewGuid().ToString();
 
		docList.Add(key, new ReportDocumentInfo(key, reportDoc));
 
		return key;
	}
 
	public void Remove(string key)
	{
		Debug.WriteLine("Remove() called.");
 
		if (key != null)
		{
			try
			{
				ReportDocumentInfo reportInfo = docList[key];
 
				DisposeReportDocument(reportInfo);
 
				docList.Remove(key);
			}
			catch (Exception e)
			{
				Debug.WriteLine("Remove() error: " + e.Message);
			}
		}
		else
		{
			Debug.WriteLine("Remove() error: null key");
		}
	}
 
	public bool Contains(string key)
	{
		return docList.ContainsKey(key);
	}
 
	public ReportDocument GetValue(string key)
	{
		ReportDocumentInfo value = null;
		if (docList.TryGetValue(key, out value))
		{
			if (value != null)
				return value.ReportDoc;
			else return null;
		}
		else
		{
			return null;
		}
	}
 
	protected void DisposeReportDocument(ReportDocumentInfo reportInfo)
	{
		try
		{
			if (reportInfo != null)
			{
				//Need to dispose document, crystal has a limit for number of loaded reports
				reportInfo.ReportDoc.Close();
				reportInfo.ReportDoc.Dispose();
			}
		}
		catch (Exception e)
		{
			//TODO: log
			Debug.WriteLine("DisposeReportDocument() error: " + e.Message);
		}
	}
 
	//Release crystal resources when cache is clean
	public void CacheRemovedCallback(string key, Object value, CacheItemRemovedReason reason)
	{
		Debug.WriteLine("CacheRemovedCallback() called, reason: " + reason.ToString());
 
		try
		{
			if (docList != null)
			{
				Debug.WriteLine("CacheRemovedCallback() cleaning ressources " + docList.Count);
 
				Dictionary<string, ReportDocumentInfo>.ValueCollection valueColl = docList.Values;
 
				foreach (ReportDocumentInfo reportDocInfo in valueColl)
				{
					DisposeReportDocument(reportDocInfo);
				}
			}
		}
		catch
		{
			Debug.WriteLine("CacheRemovedCallback() error.");
		}
	}
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of RiteshShah
RiteshShah
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you!!!
What is the namespace for ReportDocumentInfo? I am getting the following error '"The type or namespace name 'ReportDocumentInfo' could not be found (are you missing a using directive or an assembly reference" when i try compiling your code.
no namespace for that. You have to create on separate class for the code I gave you in post id 24085797. I have created ReportDocumentFactory.cs file under my APP_code folder of my website.
i have created a separate class, but i get the following error "The type or namespace name 'ReportDocumentInfo' could not be found (are you missing a using directive or an assembly reference"
where did you put that class? and what is the name you gave to that class? I would recommend you to put it under app_code folder in root of your web directory. and give it a name ReportDocumentFactory.cs. Once you generate ReportDocumentFactory.cs file, copy my code which is in post # 24085797 and paste it in ReportDocumentFactory.cs
I created the class within the root directory and the class is within the App_Code folder. Is the 'ReportDocumentInfo'  a variable which supposed to be declared with the class? Dictionary<string, string> so I presume 'ReportDocumentInfo'  is a string?
reportdocumentinfo is another class and again needs to be save under app_code folder with name ReportDocumentInfo.cs

sorry I forget to attach its code before. below given is the code. Moreover, don't put any class under direct root folder
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using CrystalDecisions.CrystalReports.Engine;
using System.IO;
using System.Text;
using System.Web.Caching;
using System.Diagnostics;
 
/// <summary>
/// Summary description for ReportDocumentInfo
/// </summary>
public class ReportDocumentInfo
{
    private string key;
    private ReportDocument reportDocument;
    private DateTime date;
 
    public ReportDocumentInfo(string key, ReportDocument reportDocument)
    {
        this.key = key;
        this.reportDocument = reportDocument;
        this.date = DateTime.Now;
    }
 
    public ReportDocument ReportDoc
    {
        get
        {
            return this.reportDocument;
        }
        set
        {
            this.reportDocument = value;
        }
    }
 
    public DateTime Date
    {
        get
        {
            return this.date;
        }
        set
        {
            this.date = value;
        }
    }
 
    public string Key
    {
        get
        {
            return this.key;
        }
    }
}

Open in new window

thank you, makes much more sense now. Another thing i want to ask you is, when you instantiate the class ReportDocumentFactory, was it not suppose  to be as follows
ReportDocumentFactory reportDocumentFactory=new ReportDocumentFactory (cache);
since the class ReportDocumentFactory expects an argument.

I have added your code and it is still not functional, therefore i am asking this question.
yes you can do like that also

ReportDocumentFactory reportDocumentFactory = new ReportDocumentFactory(this.Cache);

in aspx code I gave you, I have delare the class first and that instantiated. but you can do it in same line.