Serge’s Technology View

Talk about Technologies, Software, Product Management, and more

Visual Studio 2008 and IIS 7

Deploying ASP.Net applications is always fun when it comes to packages which are more complex then usual and require additional actions taken and this one is not an exception.

I think this topic run into the ground, but it seems to come back again and again. I guess the reason for that is “default” state set for the environment…

After upgrade of operating system to Vista IIS 7 would be installed. This brings some “inconveniences” into usual development process. Aside from worrying about disabling UAC, few other things usually breaks.

One of them is that setup package for ASP.Net application created in Visual Studio starts to fail with the error that installer session closed improperly and process has to be restarted (or similar).

If we look into installer log (check here on how to enable debug mode) the following error could be found:

Action 11:18:53: WEBCA_SetTARGETSITE.
Action start 11:18:53: WEBCA_SetTARGETSITE.
MSI (c) (B4:A4) [11:18:53:657]: Note: 1: 2235 2: 3: ExtendedType 4: SELECT `Action`,`Type`,`Source`,`Target`, NULL, `ExtendedType` FROM `CustomAction` WHERE `Action` = ‘WEBCA_SetTARGETSITE’
MSI (c) (B4:A4) [11:18:53:661]: Creating MSIHANDLE (1) of type 790542 for thread 4260
MSI (c) (B4:4C) [11:18:53:662]: Invoking remote custom action. DLL: C:\Users\SDOSYU~1\AppData\Local\Temp\MSI2978.tmp, Entrypoint: SetTARGETSITE
MSI (c) (B4:F0) [11:18:53:666]: Cloaking enabled.
MSI (c) (B4:F0) [11:18:53:666]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (B4!14) [11:18:53:726]: Creating MSIHANDLE (2) of type 790531 for thread 4116
INFO   : [01/02/2009 11:18:53:726] [SetTARGETSITE ]: Custom Action is starting…
INFO   : [01/02/2009 11:18:53:727] [SetTARGETSITE ]: CoInitializeEx - COM initialization Apartment Threaded…
ERROR  : [01/02/2009 11:18:53:729] [SetTARGETSITE ]: FAILED: -2147221164
ERROR  : [01/02/2009 11:18:53:730] [SetTARGETSITE ]: Custom Action failed with code: ‘340′
INFO   : [01/02/2009 11:18:53:731] [SetTARGETSITE  ]: Custom Action completed with return code: ‘340′

Very informational… Who would guess that it simply comes to support for IIS 6 API. In IIS 7 it called “IIS 6 Management compatability”.

Usually this module is not installed by default and we have to actually enable it.
Very simple and very quick solution is to go “Control Panel\Programs and Features\Turn Windows features on or off” and then click the check box.

iis7support

There is one more problem which may be encountered on 64 bit machine - support for 32 bit assemblies is disabled by default. To reenable, change Application Pool Defaults for your IIS 7 installation:
32bitaspon64bitos

Crystal Reports 2008 : hacking datetime parameter format - reloaded

Few weeks ago I have wrote on how to hack Crystal Reports 2008 ASP.Net Viewer control to suppress time part in the parameter calendar control.

With release of Service Pack 1 for Crystal Reports 2008, suggested solution no longer works since structure of the files has been changed.

So I went digging around again. Forgot to mention last time, but in situations like this, scripting debugging supported in Visual Studio really helps (if you are not familiar with JS debugging check following links [1] [2] for more info.

Note. It is interesting to observe how code is changing over time. And after some analisys, I would say that SAP development team is one click away from adding ability to suppress time parts for datetime parameters: only one thing missing - new property on parameter level which would allow specify how to treat it (date, time or datetime). Question is if they will decide to do so.

I will be using Visual Studio 2008 and run against my WebDev.WebServer.

After creating simple CrystalReports ASP.Net application with report which has datetime parameter, lets see what exactly is happening here.

Step 1 Step 2

Let’s run an application up to the point when engine would request parameter values being entered (Img 1).

And then let’s open Solution Explorer in Visual Studio (Img 2).
You would notice a few JavaScript files, where one we were looking for - promptengine_calendar2.js.

While having page open, dbl-click on the file in Solution Explorer and look around. (In my case actual file location is C:\Windows\Microsoft.NET\Framework\v2.0.50727\ASP.NETClientFiles\crystalreportviewers12\prompting\js\, but may vary.)

Internal Calendar control (which reside in Calendar.js file) relay on setShowTime method to manage visibility and behaviour of the calendar and this is where we will “hack” our way in.

As usual code below only highlights changes to the code in promptengine_calendar2.js file.
This time I am making no changes to the data, only how it is displayed and extracted from the calendar control. And it seems to work much better then prior solution.
Make sure you have the copy of original file backed up.

/** First, lets add one more variable to control data flow **/
    bobj.prompt.Calendar = function
    ...
       this.isDateTimeData = false;
    }
...
    /** While suppressing DateTime format we still need to know original type of the data **/
    setIsDateTime : function(isDateTime) {
       // this.isDateTime = isDateTime;
       this.isDateTimeData = isDateTime;
       this.isDateTime = false;
    },
...
    /** while suppressing time part, it is still need to be returned back in to parameter form **/
    _getStringValue : function(dateValue) {
        var format = this.isDateTime ? this.dateTimeFormat : this.dateFormat;

        if ((!this.isDateTime) & this.isDateTimeData) {
                format = format + ' 00:00:00';
        }

        return  bobj.external.date.formatDate(dateValue, format);     
       
    },

Changes are very isolated and allows a) hide time entry box and b) properly return data back into parameter form.

This solution is generic and applies to all datetime parameters visible. As a result, calendar control become for date entry only, while resetting time portion. User can still enter time part if necessary, but on the page level.

Again, make sure that file with changes we just made is replaced everywhere. Depend on your development and production environment you may have few other locations for it.

Forum has been decommissioned

Forum (http://forum.dragonsoft.us ) has been decommissioned.

For next few months we are going to keep a forward to this blog, after that sub-domain location would be deprecated.

Crystal Reports 2008, ASP.Net and impersonation

We have created our perfect reporting solution using Crystal Reports 2008 viewer control, tested everything, and  deployed it into production environment… and it is working… until Friday night… life is not perfect, especially when it comes to software.

Note. Information below is provided for both IIS 6 and IIS 7 along with 32 and 64 bit Windows environment. Make sure you are using proper reference.

For some strange reasons, big things happen when nobody anticipate it anymore (usually about a week after an initial deployment).

After usual management meeting, requirements are changed and now we wants you to protect our precious information and grant access to to some users only.

As an ASP developer you immediately turn to <IMPERSONATE> option of ASP.Net… and this is where it become interesting.

When we would test it locally, most likely everything would be fine and not cause any problems, but being deployed in production we may start to see some strange errors.

Some of them are listed below:

  • Load Report Failed
  • System.Runtime.InteropServices.COMException: Invalid file name
  • Exception Details: System.Runtime.InteropServices.COMException: Access is denied.

When we check the ASP.Net Stack Trace (we need debug/trace mode), first line may look like that: ”CrystalDecisions … ReportClientDocumentClass.Open”.

Browsing support information on SAP web-site may not give much, as well as many web-references since they now are invalid links due to changes in site map. As a result some good effort would be involved…

As you noticed, errors above do not give you much to follow upon. Nice job!

What it comes to is that Crystal Reports engine requires access to some network and local file resources - famous User TEMP folder.

With network permissions, it is usually easy and it would first thing to check:

  • Check that account used for impersonation has access to any network file locations which may be involved.

With User TEMP folders it may be not so trivial.

Depend on the version of the Windows used on local and/or server, location of it may vary: C:\WINDOWS\Temp for older versions, or more elaborate ”C:\Documents and Settings\…” and “C:\Users\…” with latest versions. And for last two, one would have to guess which user account location has to checked. Yet, most likely it would be under account IIS is using.

Why would IIS/Crystal Reports engine need access to it?

Short answer - because CR engine keeps cache of report files snapshots.
Do a little experiment, without impersonation enabled, check Temp folders when report is visible in the Viewer.
You may notice  files like ”<Report Name> {GUID}.rpt” appear and disappear.

Similar folder would be used on the server side, and this folder we would need to give permission ASPNET account (default setting) access to. Refer to this Microsoft page for additional information about ASP.Net security.

  • Account above should be allowed create/modify/delete files in TEMP folder.
  • In case of IIS 7.0, Temp folder location would be different, but approach would be the same.
    Proper default location would be %windir%\serviceprofiles\networkservice\AppData\Local\Temp as described here.

What we want have full control over temp file location?

Visit the following location:

HKEY_LOCAL_MACHINE\SOFTWARE\Business Objects\Suite 12.0\Report Application Server\InprocServer

or in case of 64 bit Vista (not being familiar at first with new registry structure you may be surprised about this)

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Business Objects\Suite 12.0\Report Application Server\InprocServer

then add/update the following value

TempDir: String = “your folder”

This will tell engine which folder to use. And then by granting MACHINE\ASPNET account rights to create and manipulate files in it we would solve the grand problem.

Restart your web server and you should be good to go.

Notes:

  1. Solution above can be used for any prior version of Crystal Reports, but may require minor adjustments.
  2. Problem with permissions could also cause broken image links in the Viewer
  3. Depend on configuration, permissions could be required for NETWORK SERVICE account and/or IIS_WPG group.

Valid XHTML 1.0 Transitional  Valid CSS!