One of the most frustrating things about Crystal Reports is how challenging it is to create a report on the fly. I mean really on the fly. Like from scratch. Many people have said it can’t be done. With Crystal Reports 2008 (CR XII) it can be done, but only with the use of a report server. Or at least that is the best that I have been able to determine so far. The trouble is, most of us don’t have dedicated Crystal Report Servers, or the desire to set them up.
SAP says in it’s help files, that we can create a report on the fly using the Report Application Server (RAS), which runs on the client side. I don’t know if they’ve tried to actually do this, but nobody I know has gotten it to work. That said, there’s a very easy way of getting around this. Save a blank .rpt and embed it into your project. Now whenever you need to create a report, you simply use the embedded completely blank .rpt to start, and go from there.
Of course, this means you need to be able to embed a file, write it out to disk temporarily, and then read it back in. This page will walk you through this process.
For the purposes of this Tutorial I will assume the following things:
- You already have the file you want to embed and know it’s disk location.
- Your project will have access to a disk location to temporarily write the file to.
Create a project or a class to handle your embedded file.
Add your file to your project by right-clicking in the Solution Explorer panel where you’d like the file to be emedded. In my case it’s in my EmbeddedFiles project.
Select “Add”–>”Existing Item”

Navigate to the location of your File in the File Dialog. You may need to change the filter to All Documents .* in order to see your file.

Select your file and click “Add”
Right-click on your new file and select properties.

Verify that the new file is set to the following properties:
| Build Action: | Embedded Resource |
| Copy to Output Directory: | Do Not Copy |

Add a Resource File to your project.


Open your resource file and add a value baseFilePath with the namespace of your project up through the location of your file. For my project it’s “theogeer.EmeddedFiles.file.”. This will allow you to put as many files as you want in this location and call them using the same baseFilePath value.

Once you set all that up we can write our class. The concept is really simple. When the class is constructed it will take the embedded file and write it to disk. When the class is destructed it will delete the file. While the object you’ve created exists you can access it using System.IO.File as with any other file on disk.
Let’s start by setting up a string value to hold the FilePath of the temporary file on disk. I’ll use a private string for the defining path, and expose it publicly as TemporaryFilePath. In order to assure that we don’t mess ourselves up by calling the same embedded file twice we’ll add a timestamp to the file by using a method to set the temporary path.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /// <summary> /// temporaryFilePath is the private string where we will write the temporary version of the file. /// </summary> private string temporaryFilePath; /// <summary> /// The TemporaryFilePath for the temporary version of the file. /// </summary> public string TemporaryFilePath { get { return temporaryFilePath; } } /// <summary> /// Set the temporary fileName with a unique timestamp to prevent a conflict /// </summary> /// <param name="fileName">The file name</param> private void setTemporaryPath(string fileName) { string folder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", ""); string timestamp = DateTime.Now.ToString("_yyyy_MM_dd_hh_mm_ss_ffff"); fileName = fileName.Insert(fileName.LastIndexOf("."), timestamp); temporaryFilePath = string.Concat(folder, Path.DirectorySeparatorChar, fileName); } |
For our constructor we need to create a stream reader from our embedded file, and use a binary reader and writer to to write the embedded file out byte by byte.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// <summary> /// Retrieve an Embedded File from the project /// </summary> /// <param name="fileName">The name of the embedded resource to write out to disk.</param> public RetrieveEmeddedFile(string fileName) { string internalPath = string.Concat(resource.baseFilePath, fileName); setTemporaryPath(fileName); FileStream fs = new FileStream(temporaryFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); Stream reader = this.GetType().Assembly.GetManifestResourceStream(internalPath); BinaryReader br = new BinaryReader(reader); BinaryWriter bw = new BinaryWriter(fs); for (int i = 0; i < reader.Length; i++) bw.Write(br.ReadByte()); br.Close(); bw.Close(); } |
Because we write a file to disk on Construction, we need to delete that file on Destruction.
1 2 3 4 5 | ~RetrieveEmeddedFile() { if (File.Exists(temporaryFilePath)) File.Delete(temporaryFilePath); } |
Below is the entirety of my class. We could add a lot more to this. I considered a CopyTo function that would implement File.Copy() but decided KISS was the way to go here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace theogeer.EmbeddedFiles { /// <summary> /// Get a temporary file from an embedded resource. /// </summary> public class RetrieveEmeddedFile { /// <summary> /// temporaryFilePath is the private string where we will write the temporary version of the file. /// </summary> private string temporaryFilePath; /// <summary> /// The TemporaryFilePath for the temporary version of the file. /// </summary> public string TemporaryFilePath { get { return temporaryFilePath; } } /// <summary> /// Set the temporary fileName with a unique timestamp to prevent a conflict /// </summary> /// <param name="fileName">The file name</param> private void setTemporaryPath(string fileName) { string folder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", ""); string timestamp = DateTime.Now.ToString("_yyyy_MM_dd_hh_mm_ss_ffff"); fileName = fileName.Insert(fileName.LastIndexOf("."), timestamp); temporaryFilePath = string.Concat(folder, Path.DirectorySeparatorChar, fileName); } /// <summary> /// Retrieve an Embedded File from the project /// </summary> /// <param name="fileName">The name of the embedded resource to write out to disk.</param> public RetrieveEmeddedFile(string fileName) { string internalPath = string.Concat(resource.baseFilePath, fileName); setTemporaryPath(fileName); FileStream fs = new FileStream(temporaryFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); Stream reader = this.GetType().Assembly.GetManifestResourceStream(internalPath); BinaryReader br = new BinaryReader(reader); BinaryWriter bw = new BinaryWriter(fs); for (int i = 0; i < reader.Length; i++) bw.Write(br.ReadByte()); br.Close(); bw.Close(); } ~RetrieveEmeddedFile() { if (File.Exists(temporaryFilePath)) File.Delete(temporaryFilePath); } } } |
Here is the Visual Studio 2008 project file for the project this far.
Click here to download.
One Trackback
[...] Crystal Deconstructed My experiments in automating Crystal Reports 2008 Skip to content Are you trying to automate Crystal? You’re not alone « Embedding a File in Visual Studio 2008 [...]