Friday, October 29, 2010

Getting Jiggy with Ajax and fields

I was asked to do something that I’ve done a million times before the other day, link a drop down field to a radio button so depending on what is selected the list of option should reduce. I decided to use Ajax and JQuery to do all the hard work and also because its really good at what it does.

The first requirement was to have a number of radio buttons on screen each showing the name of a department. These were very simple at first, not even taken from the database. So I created a very simple bit of HTML…

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Ajax Demo</title>
</head>
<body>
Corporate <input type="radio" id="radio1" name="BU" value="Corporate" /><br />
Food <input type="radio" id="radio2" name="BU" value="Food" /><br />
Investment <input type="radio" id="radio3" name="BU" value="Investment" /><br />
<select id="department">
<option value="0">-- No business unit selected --</option>
</select>
</body>
</html>

Nothing crazy here, just your basic setup, with three radio buttons and a select box with no values. It would look like this.

image

Adding the Ajax bit

Now we need to implement JQuery onto the page, and we do this by including the latest script file. You can get this on the internet, via a content delivery network or just download it. I’ve taken a copy as its quicker.

<script type="text/javascript" src="template/scripts/jquery-1.4.2.min.js"></script>

The line above adds the JQuery script into the page your are working with.

Below is the script to do all the wor, I’ve highlighted the interesting bit.

<script type="text/javascript" language="javascript">
$(document).ready(function() {
$("input[name*='BU']").click(function() {
callAjax($(this).val());
});
});

function callAjax(val) {

var selectedValue = val;
var servletUrl = '/OrganisationChartDataService.svc/Departments/'">http://<server>/OrganisationChartDataService.svc/Departments/' + val + '/JSon';

$.getJSON(servletUrl, function(options) {
var department = $('#department');
$('>option', department).remove(); // Clean old options first.
$.each(options, function(index) {
department.append($('<option/>').val(options[index].Id).text(options[index].Name));
});
});

}

</script>

The first section binds a “click” function to any element on the page with the name “BU”. This is handy because we don’t have to write a separate function for each element and if we add more we don’t have to do anything, it will just work.

The second highlighted bit is teh call to a WCF web service that takes in the name of a business Unit as being part of the URL, what’s returned can then be added to the select list.

The results can be see below, its fast simple and very powerful.

image

clicking another item shows this:

image

Wednesday, October 20, 2010

Old school CSV without creating a temp file

I had a request to export a report out to Excel today, which is something I’ve done a bunch of times before but always by producing a temporary file.  I figured I’d try something different, find a way to give me the same functions without having to worry about permissions on the file system, or deleting the files afterwards.

It turned out to be very easy… use a TextStream that writes out  a HTML header so Explorer does all the hard work.

On the ASPX page…

On the click event for the export button we turn off the usual ASP.NET view state stuff and make a new header with the content type of "application/vnd.ms-excel", this tells IE to start Excel regardless of the details sent.  Another interesting thing to see here is the Response.End call, you’ll need this to prevent ASP.NET sending the page refresh information along with your data.

protected void ExportButton_Click(object sender, EventArgs e)
{
      this.EnableViewState = false;
        Response.Clear();
        Response.Buffer = true;
        Response.ContentType = "application/vnd.ms-excel";
        Response.AddHeader("Content-Disposition", "inline;filename=TeamExport.csv");
        team.ExportToExcel(Response.Output, true);
        Response.Charset = "";
        Response.End();
}

On the Business Object its a simple matter of building up an array of results, making sure to wrap them in “” for each field.  Then added this to the HTML TextStream …..

/// <summary>
/// Export Global Team lists to Excel
/// </summary>
/// <param name="httpStream">The HTTP stream.</param>
public void ExportToExcel(TextWriter httpStream)
{
     // find all associated applications
     IList<Application> applications =  (from application in Application.FindAllByProperty("GlobalTeam", Id)
             select application).ToList<Application>();

     foreach(Application app in applications)
     { 
         string[] dataArr = new string[]
             {
                 WriteableValue(app.Id),
                 WriteableValue(app.GlobalTeamName),
                 WriteableValue(app.Title),
                 WriteableValue(app.SupportManager),
                 WriteableValue(app.ProjectManager),
                 WriteableValue(app.StartDate.ToShortDateString()),
                 WriteableValue(app.EndDate.ToShortDateString())
             };
         httpStream.WriteLine(string.Join(",", dataArr));
     }
}

public static string WriteableValue(object o)
{
    if (o == null || o == null)
        return "";
    else
        return "\"" + o.ToString() + "\"";
}

Its good to rediscover something old, simple but yet works so well ….

Thursday, October 14, 2010

More pain with Windows x64 migration

You have no idea how hard it was to get this to work!.  following on from my last posting I moved over from Windows XP to Windows 7 on x64 for development.  Although there was some pain in setting up the VB COMs it was nothing to the suffering when it comes to Registry settings.

Some applications were continually giving Generic 500 errors with little or nothing in the Event Logs, so I presumed it was a security problem.  Following many hours of messing about, it turns out I was on the wrong track altogether.  The specific COMs were failing because they were looking for Registry settings…

All the settings had been imported into their usual position under HKEY_LOCAL_MACHINE\SOFTWARE\SomeApplication, but no matter what I did the values always came back null. 

The solution

The answer was hidden away in a MS support article (http://support.microsoft.com/kb/896459)

32-bit programs and 64-bit programs that are running on an x64-based version of Windows operate in different modes and use the following sections in the registry:

  • Native mode 64-bit programs run in Native mode and access keys and values that are stored in the following registry sub key:
    HKEY_LOCAL_MACHINE\Software
  • 32-bit programs run in WOW64 mode and access keys and values that are stored in the following registry sub key:
    HKEY_LOCAL_MACHINE\Software\WOW6432node

So adding a copy of the REG settings to this second location made everything work again.

Tuesday, October 5, 2010

Setting up Windows 7 for Classic ASP

I’ve decided to move over from using the slow VPN to local development so decided to setup some old classic ASP applications on my local machine which is running IIS 7.5.  Unfortunately this process was far from easy.

Setting up IIS

First you need to be able to activate all the required roles.  You do this by selecting Control Panel/Programs/Turn Windows features on or off.  from the list you select the following:

Parallels Picture

Doing some configuration

Next you should create an Admin Console for you to work with.  Type  “MMC” into the start menu and select File/Add Remove Snap in from the menu.  Select IIS Manager and IIS Manager Ver.6, Also choose Event Log for the current machine.

Parallels Picture 1

File Save this to your desktop for later.

Getting it working

When I got a local copy of the application all the .NET code worked first time without any issue, however when I tried to run any Class ASP code I got a standard Error: This error (HTTP 500 Internal Server Error) means that the website you are visiting had a server problem which prevented the webpage from displaying.

After some checking about on the net it turns out that you can turn on messages for ASP code using a configuration setting in IIS Manager,

Within IIS Manager Browse to the Virtual Directory you need and Double click click on the ASP icon and expand the “Debugging Properties” tree.

Parallels Picture 2

Turn on “Log Errors to NT Log” and “Send Errors to Browser”.

Unfortunately after doing this I still did not get an error messages displayed so had to do some more hunting down of the error.

Tracing requests

You also need to turn on Tracing which can be done by reading the instructions on the following link: http://learn.iis.net/page.aspx/565/using-failed-request-tracing-to-troubleshoot-classic-asp-errors/

Following this you actually get to see a correct error!

Parallels Picture 3

LineNumber:21
ErrorCode:800a01ad
Description: ActiveX component can't create object

Checking the global.asa gave me the following line:
Set GetDirectory = Server.CreateObject("EnterpriseIreland.BusinessObjects.HumanResources.Directory")

Checking Permissions

This error is usually down to permissions or the worker process can’t find the DLL.  Setting “Everyone” with Full permissions on the D:\Applications\ folder did not work, neither did giving “Everyone” access to the D:\Development folder.

Next I checked to make sure the DLLs were correctly registered by re-running  the “register_assembly.bat” command file located with in the D:\Applications\Common folder.

Next open Regedit.exe and browse to the DLL that was failing:
HKEY_CLASSES_ROOT\EnterpriseIreland.BusinessObjects.HumanResources.Directory open the CLSID key and you find a GUID.  In my case it was “{C940B037-A429-303E-8B2E-162E4E19AC91}” search the registry for this GUID.

You should find it somewhere in the HKEY_CLASSES_ROOT\Wow6432Node\CLSID\ key group; in my case it was here: HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{C940B037-A429-303E-8B2E-162E4E19AC91} click into the “InprocServer32” key and look for the value key “Codebase” this should show the file location of the DLL.  If it’s not pointing to the correct location change it.

Moving to App Pool

None of these fancy changes seemed to make any difference so I decided to look into the AppPool configuration.  The DefaultAppPool was working fine with .Net, so I created a second one based on this called “ASP”.

Parallels Picture

Next in the Advanced settings you need to make one minor but VERY IMPORTANT change;

Parallels Picture 1

You must set “Enable 32-bit Applications” to “True”

Finally assign your website to use this application pool by selecting it in IIS Manager and click Basic Settings in the Action Menu.

Parallels Picture 2

Click Select and choose “ASP” or whatever your AppPool name is called.

Success At last!!

After all this, we finally have a working legacy ASP site working on Windows 7.