Andornot Consulting Inc.
Home Page
Home Page
 |  | 

Tuesday, November 21, 2006

Vista really is this easy to install...

Thursday, November 09, 2006

Copying MARC Transformer maps

If you would like to transfer MARC Transformer maps from one computer to another, simply copy the MTrans.as0 file from the MARC Transformer program directory on your computer and overwrite the other version on the other computer. (Remember to make back-up copies of the MTrans.as0 files just in case).

Wednesday, November 08, 2006

Install Multiple IEs

IE7 is here and I thank any and all merciful deities who may have had a hand in that deal, but the suck that was IE6 has not gone away forever yet.

When you install IE7 it overwrites IE6. In the main, this is a good thing. For someone who needs to continue testing features in IE6, ees no so good.

Fortunately, others have pioneered the way and here is a very handy way to install multiple versions of IE right on back to IE 3.0, if you enjoy that sort of pain.

Multiple IE installer

Amazon Web Services

So I went to the Victoria .NET Developers Association meeting last night, and their guest speaker was a dev evangelist from Amazon Web Services. That is not to say Amazon.com, but rather the computing services division that is the public face of the vast infrastructure that has been built over the years to support Amazon.com and its satellite businesses. Web Services now has a life of its own, and is attempting to move the goalposts closer together in the web computing game.

S3 - Simple Storage Service

S3, or Simple Storage Service, houses data safely and securely across their distributed network. That doesn't sound very exciting until you start to realize how incredibly cheap, reliable and powerful it is compared to DIY data storage. As to cheap, 15 cents per GB per month, and 20 cents per GB to move data in or out. As to reliable, their network is so large the entire continent of North America would have to sink beneath the waves before your data was lost. Due to the fact that you do not rent space on any particular machine, you are not tied to a given machine's success or failure. Most larger organizations have a data center facility with backup, redundancy, and failover machines, but it's very expensive! As to powerful, bandwidth is very large, and there is literally no practical limit on the amount of data you can store. Terabyte? Sure. The speaker gave some examples of web businesses that had saturated either their SAN storage facility or their bandwidth, and removed the bottlenecks at a stroke by relying on S3 instead.

EC2 - Elastic Computing Cloud

EC2, or Elastic Computing Cloud, is in beta, but will be something to watch. It's a web service that runs virtual server instances. As many as you want, for cheap: 10 cents per hour per instance. Again, all the benefits of S3 apply. At this point only Linux based virtual machines are supported, so I hope it opens up to Windows instances in the future. The speaker had a new webserver instance going in 10 minutes. Woah!

These services are really going to be hard to ignore, for both large and small web-based businesses. It's just so much power and convenience for so cheap.

Thursday, November 02, 2006

Query String tips with C# 2.0

I switched from VB.NET to C# a few months ago because of the JetBrains Resharper Visual Studio add-in.

C# has been a joy for the most part. I am occasionally stumped because it is stricter than VB.NET, but working through such challenges makes me understand the C# language and .NET framework better.

Ted and I, and I guess other asp.net developers, work with query strings a LOT. I discovered a couple of new methods in .NET 2.0 that are helping me out with the HttpRequest.QueryString collection.

String.IsNullOrEmpty(string): bool

A typical scenario is to init a string, pass it a query string value, and then check to see that the string has a value. I'm always trying to remember whether a non-existent query string key returns null, or an empty string. Or if the key is there but has no value, is that null or an empty string? With String.IsNullOrEmpty, I don't have to think:

string CheckId = Request.QueryString["ID"];

if (string.IsNullOrEmpty(CheckId) == false)

{

    //do stuff

}

Int32.TryParse(string, out Int32): bool

In the code example above, I want an ID value, which I need to be a integer. I want to test that it is a number before proceeding, and I also want to actually convert it to an integer. In the past I would use VB.NET's IsNumeric, and then Int32.Parse(string) in a try/catch block. What a pain. Int32.TryParse simultaneously tests the input string for integericity, returning a boolean, and outputs the integer result (zero if the string can't be parsed):

int i;

if (int.TryParse(CheckId, out i))

{

    //do stuff with i

}

Field names in XML: CS vs. DB/WebPublisher

Tip: avoid spaces in field names.

When a field is referenced in WebPublisher XML, any space in the field name is replaced. In DB/Text WebPublisher XML, the space is replaced by a hyphen: "-". In CS WebPublisher XML, the space is replaced by an underscore: "_".

Thus, when converting an existing DB/Text Webpublisher XML-based service to CS, if the service expects field names with hyphens, things tend to go "boom crumple bang squish".

Reminder: avoid spaces in field names.

Wednesday, November 01, 2006

Desktop scripting: link on ID, but search by name

I've been using this technique a lot lately, so why not share it?

When linking a textbase to another, it's best to link on a unique ID: something that won't change over time. The plus side is that the link from primary to secondary textbase will not be easily broken. This is just good sense and a long-time database design golden rule. (What if you linked to a Name field and someone changed their name?)

The down side is that an ID is not people-friendly. When the time comes to link out to the secondary textbase, a number like "123" means a lot less to human eyeballs than "Smith, John". Inmagic gives you the ability to browse the available items to link to, but a list of numbers is next to useless. How do you know that "123" is the Record ID for "Smith, John"? You don't.

To retain the strength of the link-on-ID and the user-friendliness of browse-by-name, we call upon JAVASCRIPT. Hurrah. Here's what I do in edit forms. I'll use an example based on a library sign-out page: there is a Catalog, a Borrowers textbase and a Loans textbase. The Loans textbase is primary, but links to Catalog and Borrowers textbases as secondary textbases. I want to create a loan record that links to the Borrower via Borrower ID, but I don't want the user to have to know the Borrower's ID. I want them to search by borrower name to make the link.

Fig. 1. Link is made on Borrower ID, but user can search by Borrower name or barcode and the script will make the link.

In this case I give the user the opportunity to search either by name or barcode. If the script finds a single match, it automatically populates the Borrower ID field. If it finds multiple matches, it displays the top 5 so the user can either re-search with a more specific search or copy-and-paste the ID themselves.

Fig. 2. User has searched for "doe" and found 2 matches.

Here is the script which performs the search on borrower name. I have defined an object of type "Borrrower" to encapsulate all the information I need about a borrower and this function returns an array of these Borrower objects.

function GetBorrowersByName(name) //returns array of Borrower

{

    var names = name.replace("\r", " ").split(" ");

    var rs;

    var fldBorrowerID, fldBarcode, fldLastName, fldFirstName, fldMiddleName, fldPatronType, fldPatronStatus;

    var strNames = names.join(" / ");

    var output = [];

 

    rs = Application.newRecordset(userTextbase, Application.activeTextbase.path, userPassword);

    if (rs != null)

    {

        rs.Open("Find (LastName ct " + strNames + ") or (FirstName ct " + strNames + ") or (MiddleName ct " + strNames + ")");

        DebugLog("Find (LastName ct " + strNames + ") or (FirstName ct " + strNames + ") or (MiddleName ct " + strNames + ")");

        if (rs.Errors.Count > 0)

        {

            DebugLog("GetBorrowersByName: " + rs.Errors(0).Description);

        }

        else if (rs.RecordCount > 0)

        {

            rs.MoveFirst();

            while (!rs.EOF)

            {

                fldBorrowerID = rs.Fields("RecordID");

                fldBarcode = rs.Fields("Barcode");

                fldLastName = rs.Fields("LastName");

                fldFirstName = rs.Fields("FirstName");

                fldMiddleName = rs.Fields("MiddleName");

                fldPatronType = rs.Fields("PatronType");

                fldPatronStatus = rs.Fields("PatronStatus");

                output[output.length] = new Borrower(fldBorrowerID.Value, fldBarcode.Value, fldFirstName.Value, fldMiddleName.Value, fldLastName.Value, fldPatronType.Value, fldPatronStatus.Value);

 

                rs.MoveNext();

            }

        }

        rs.Close();

    }

    return output;       

}

 Fig. 3. GetBorrowersByName function, searches Borrower textbase and returns an array of Borrower objects

Here is the script which contains the logic to decide what to do with the results. Again, if single match is found, the Borrower ID is populated automatically, and if multiple matches are found, the top 5 are shown to the user in the gray background box (called boxBorrowerInfo in the script).

function ShowBorrowerResults(results)

{   

    if (results.length < 1)

    {

        selectedBorrower = null;

        Form.boxes("boxBorrowerID").content = "";

        Form.boxes("boxBorrowerInfo").content = "No match found";

    }

    else if (results.length == 1)

    {

        selectedBorrower = results[0];

        Form.boxes("boxBorrowerID").content = results[0].BorrowerID;

        Command.refreshWindow();

    }

    else if (results.length > 1)

    {

        selectedBorrower = null;

        Form.boxes("boxBorrowerID").content = "";

        Form.boxes("boxBorrowerInfo").content = "Matches:";

        for (i = 0; i < results.length;i++)

        {

            if (Form.boxes("boxBorrowerInfo").content != "")

            {

                Form.boxes("boxBorrowerInfo").content += "\n";   

            }

            Form.boxes("boxBorrowerInfo").content += results[i].BorrowerID + "  " + results[i].Barcode + "  " + results[i].LastName + ", " + results[i].FirstName + " " + results[i].MiddleName;

        }

    }       

}

In the single-match-found scenario, the Borrower ID is populated with the found Borrower ID, and the window is refreshed so that any secondary link information shows up.

Fig. 4. A single match has been found for "notdoe". The Borrower ID has been populated, and the secondary fields (name and borrower type) based on the link are showing.

And there you have it. Get to know the Inmagic recordset object and you can query any textbase from any other textbase.