Serge's Technology View

Talk about Technologies, Software Architecture and Management

For Trader Joe’s fans

As a long time customer of Trader Joe’s I just love this :)

When I moved from CA, this was first thing we started to look for and unfortunately had to travel two hours to Chicago until TJ opened local store. Talking about loyalty :)

Only if visited TJ on the constant basis for a few years you may get an irony of some verses, but, otherwise, it is very good informal commercial and consider informal style of the TJ, they should use it officially.

Two thumbs up. Enjoy

Wow! Well, what do you expect from the guy who made this

or these.

CrystalReports: getting engine version

When working on the new web-site which uses CrystalReports engine to display some reports, it is useful to know what version is used.

Yes, we usually know what version of engine we have on development machine because of the level of the control we have. With production environment, it may be not so obvious because it can be deployed by others. And at some point something may happen to the machine and environment was restored from the backup.

In all cases considered, to know what Run-time do we have at the moment without actually go and look at assemblies, may be very useful and quick check to determine the problem.

Since we are using .Net, it can be done easily by including version info into our ASP.Net page.
Lets assume we have lbCrystalVersion Label control on the page, then in the Page_Load() the following code can be added to populate information needed:

lbCrystalVersion.Text = "Crystal Reports: " + typeof(CrystalDecisions.CrystalReports.Engine.ReportObject).Assembly.GetName().Version.ToString();

As you can see, I am using ReportObject to determine current version.

In case of CrystalReports 2008 version displayed would be 12.0.2000.0

Crystal Reports Extension Methods Library

After using Crystal Reports for many years what always strikes me is that some of the methods available via API are not generic enough and require unnecessary repeated coding for simple things.

Lately all my development, when in comes to reports, is based on Crystal Reports 2008  engine within ASP.Net/C# environment. While there are many improvements in the functionality available to developers, there are still things which could be done easier. So what do we do to make our job easier? We develop set of special classes, wrappers and libraries which would simplify work with Crystal Reports API.

But disadvantage of introducing yet another helper class, is that it is another helper class. We are loosing simple inheritance of the new functionality in API and make code even more complex.
But there is a nice feature in .Net which helps avoid problem above - Extension Methods - it allows attach additional functionalities to an existing type/class even if you do not have access to the source for it.

Idea is then to keep using Crystal Report’s ReportDocument class and build on top of it by providing extra methods that can be useful when you want to integrate Crystal Reports in your .Net application.

Note #1. If you have ideas or suggestions for new methods, please let me know.
Note #2.This is work in progress and new versions would be available in the future. You can always download the latest version here.
Note #3. Library is developed and tested for Visual Studio 2008 and Crystal Reports 2008 with SP1.
Note #4. Code is self-documented using XMLDoc.

In order to introduce new methods into your code, simply compile a provided assembly and add reference in your code. After that you should see new methods listed below available for each ReportDocument instance.

Currently included:

// Assign the connection info to all tables in the report
public static void AssignTableConnections(this ReportDocument reportDocument, ConnectionInfo  connectionInfo)

// Close opened report, otherwise throw exception
public static void CloseReport(this ReportDocument reportDocument)

// Export report into file of specified format
public static void Export(this ReportDocument reportDocument, string fileName,  CrystalDecisions.Shared.ExportFormatType exportFormatType)

// Checks if specified parameter is present in the report
public static bool HasReportParameter(this ReportDocument reportDocument, string paramName)

// Function returns list of parameters descriptions with associated
// values for specified report instance in the form of HTML code block
//  which then can be used in the report to display current parameter
public static string GetReportParamsAsText(this ReportDocument reportDocument)

// Set specified report parameter
public static void SetReportParameter(this ReportDocument reportDocument, string paramName, object paramValue)

// Load report and prepare database connection using provided Server, Database Names, and login info
public static void OpenReport(this ReportDocument reportDocument, string reportFile,  ConnectionInfoType type, string serverName, string databaseName,  bool integratedSecurity, string userName, string password)

public static void OpenReport(this ReportDocument reportDocument, string reportFile, ConnectionInfoType type, string serverName, string databaseName, string userName, string password)

public static void OpenReport(this ReportDocument reportDocument, string reportFile, ConnectionInfoType type, string serverName, string databaseName)

// Purge saved report data if present
public static void PurgeSavedData(this ReportDocument reportDocument)

File locks or when garbage collection goes bad

With introduction of garbage collection (System.GC name space) in .Net, life of the Windows programmer become easy – no need to worry about releasing objects, code become simpler, etc.
In “old” time one would need to use Interfaces to achieve similar functionality and it does have some advantage even over GC – immediate garbage collection or release of allocated resources/objects.

When writing code in .Net some of us take many things for granted and not always keep in mind that many operations are performed in the context of the unmanaged code or in the “old way”…

File operations or legacy code wrappers are perfect example.
Just because library is available as managed code, it does not mean that everything has ability to “self-heal”.
For example in code file is open for edit with lock being placed.
If the file in not closed explicitly, it would be a responsibility of the owner process to release the lock at the time of releasing associated resources – when process is destroyed.

With garbage collection, just because we are no longer using/owning the process/object, it does not mean that it has been destroyed immediately after. GC management core will release object when it “feels” fit, therefore introducing latency into the process.

Off course, proper way would be to be more careful within the code and make sure any locks are released in managed and predictable way: Open/Close, Lock/Unlock, … Easy solution, but not always accessible, especially when working with 3rd party libraries.

So instead, we can force GC manager to “collect garbage” in-place with the following small code:

// See code follow up below
System.GC.Collect();
System.GC.WaitForPendingFinalizers();

What does it do?
First call will instruct GC manager to start the process (1), while second (2) will make sure that we wait for process to be completed.

In the case of the file locks, only after GC has released process which placed the lock in the first place, we can manipulate with the file (ex. delete, rename, move).

Valid XHTML 1.0 Transitional  Valid CSS!