Joe
Joe

Reputation: 83

Handling streams while Batch Printing RDLC reports from a console application

I am printing reports from a console application. I started off using the manner prescribed by Microsoft ( http://msdn.microsoft.com/en-us/library/ms252172(v=vs.100).aspx). In this technique, one renders a report like so:

report.Render("Image", deviceInfo, CreateStream, out warnings);

Where CreateStream is a callback to a function:

private Stream CreateStream(string name, string fileNameExtension, 
  Encoding encoding, string mimeType, bool willSeek)
{
    Stream stream = new FileStream(name + "." + fileNameExtension, 
      FileMode.Create);
    m_streams.Add(stream);
    return stream;
}

The idea being that you render the reports you want to files, leaving the streams open and collected in an array. Then once they are all rendered, you iterate through that array, using those open streams to send the file contents to the printer.

This works well for a few reports, but in my case, I am printing around 1500 one page reports. Obviously, I cannot leave all those streams hanging open without some serious degradation to performance. So, I modified things. I created a class level stream object (RenderStream) that I use in the CreateStream callback, and save the file name in a collection.

RenderStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Read);
RenderedFileList.Add(fileName);

I then RenderStream.Dispose() after the Report.Render() function returns.

This way my streams stay closed and disposed. And after all of my exports are done, when I go to print, in the PrintPage event I do this:

private void PrintPage(object sender, PrintPageEventArgs ev)
{
    using (Stream stream = new FileStream(RenderedFileList[fileCounter], FileMode.Open, FileAccess.Read, FileShare.Read))
    {
        Metafile pageImage = new Metafile(stream);
        ev.Graphics.DrawImage(pageImage, ev.PageBounds);
    }
}

Now, this where is the problem lies. While I usually have no problem opening streams to those rendered files, some 5% of my attempts to access those files at print-time return exceptions, reporting that the file is not accessible because it is opened by another process. Even though the prior stream has been disposed.

What can I do to get around this?

Upvotes: 1

Views: 2484

Answers (2)

SolarX
SolarX

Reputation: 1943

Why do you use a FileStream instead of a MemoryStream?

This works for me:

 private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
    {
        Stream stream = new MemoryStream();
        m_streams.Add(stream);
        return stream;
    }

Upvotes: 0

Irshad
Irshad

Reputation: 3131

I face the same problem and came out from another way around. I followed this approach refering your link..

Kept a list to get all the files created by the stream:

 private List<string> _emfFiles = new List<string>();

Modified CreateStream method to:

private Stream CreateStream(string name, string fileNameExtension, 
  Encoding encoding, string mimeType, bool willSeek)
{
    Stream stream = new FileStream(name + "." + fileNameExtension, FileMode.Create);
    m_streams.Add(stream);

    //Get all the files
    _emfFiles.Add(name + "." + fileNameExtension);

    return stream;
}

So that _emfFiles list have all the EMF files created by the stream. Then, in the Disposed method;

public void Disposed()
    {
        if (m_streams != null)
        {
            foreach (Stream stream in m_streams)
                stream.Close();
            m_streans = null;
        }

        //Delete every file created by the stream
        foreach (string file in _emfFiles)
        {
            if (File.Exists(file))
                File.Delete(file);
        }
    }

Finally called the Disposed method in the Run method:

private void Run()
    {
        LocalReport report = new LocalReport();
        report.ReportPath = "Report.rdlc";
        report.DataSources.Add(new ReportDataSource("Sales", LoadSalesData()));

        Export(report);

        m_currentPageIndex = 0;
        Print();

        //After finishing printing delete those EMF files
        Disposed();
    }

This approach works for me. Hope it helps..

Upvotes: 2

Related Questions