Dave Transom's CSharpVitamins

An occasional blog about C#, Javascript and Web Development

The YUI Simple Controls for Shared Hosting (ASP.NET)

With the release of Yahoo!'s shared hosting for YUI (Read their article: Serving YUI Files from Yahoo! Servers) I thought I'd release a couple of ASP.NET server controls (and practices) I've found as a great helper.

Firstly, I think YUI (and I say it yooey :) is a great library. It uses some tight OO patterns, and is headed by some of the key instigators in how we currently use javascript as a first class object oriented language. A couple of years ago I read Douglas Crockford's articles on javascript and started understanding the real power we have with it, and he's one key member there. So it's got some really good minds behind it. Jack Slocum also thought YUI was good, but didn't quite get enough exposure, and started building his yui-ext library with it, and damn his work is looking good, but that's another story and I digress...

There are a couple of key benefits to using the hosted YUI solution.

  1. Benefiting from the cache That is, if someone visits Yahoo!, or another site that uses the shared YUI files, instead of downloading the files anew, the browser simply loads the files from the cache - you save bytes and time!
  2. Files are served minified, compressed (gzipped) and your site or application gets to take advantage of Yahoo!'s extensive network infrastructure and caching features.
  3. Easy deployment and upgrades
    Since you don't have to deploy the entire library each time or each new version, which can be tedious if you store the entire source in with your website files, you simply provide a reference to the right version of the right file.

There are two points to be aware of though:

  1. Yahoo! currently do not provide a securely hosted set of files. They recommend serving the files from your own server if you need HTTPS.
  2. If you are worried about privacy, it's worth noting that requests for the library from your site will produce relevant log file entries and statistics for Yahoo!. Nothing too sinister there I don't think, provided you know where you stand.

Enough background already! What do I get out of this?
Well, fair enough. Thanks for your patience this far. The controls I write about are extremely simple. They're designed to make using the shared YUI library a sneeze and because YUI has a fairly frequent release cycle, it helps tackle upgrade issues.

All it really consists of is, a 'Script' control, that renders HTML script elements to your page, a YuiScript control which is complemented with a YuiScriptType enumeration. And then the same scenario for the YUI CSS files (Although with some limitations). The version of YUI to be used can be set programmatically, or via the web.config, so it makes upgrading a breeze.

How do you use it?
There are two ways. Assuming you have the tag prefix and library registered in your web.config, or at the top of your page like so:

<%@ Register TagPrefix="YUI" Namespace="Singular.Web.YUI" Assembly="Singular.Web.YUI" %>

You can simply add the YUI Scripts in your .aspx page.

<YUI:YuiScript Runat="server" Type="YahooDomEvent" Version="2.2.0" />

The version attribute can be omitted, and preferably set in the web.config, so upgrades are uniform. Alternatively, you can add scripts programmatically to the controls in the head of your page like so:

protected void Page_Init(object sender, EventArgs e)
{
    Header.Controls.Add(new YuiScript(YuiScriptType.YahooDomEvent));
    Header.Controls.Add(new YuiScript(YuiScriptType.Dragdrop));
}

If you want to go the programmatic route, I'd suggest going a little further, and add a "scripts collection" to your applications base Page class.

public abstract class PageBase : System.Web.UI.Page
{
    ScriptList _scripts = new ScriptList();
    StylesheetList _styles = new StylesheetList();

    public ScriptList Scripts
    {
        get { return _scripts; }
    }

    public StylesheetList Styles
    {
        get { return _styles; }
    }

    protected override void OnPreRender(EventArgs e)
    {
        _scripts.ForEach(Header.Controls.Add);
        _styles.ForEach(Header.Controls.Add);

        base.OnPreRender(e);
    }
}

ScriptList and StyleList are included in the attached source, but are simply wrappers of an IList<Script>.

With the example above, you can concisely add client script and style sheets to your page.

// core
Scripts.Add(new YuiScript(YuiScriptType.YahooDomEvent));
Scripts.Add(new YuiScript(YuiScriptType.Dragdrop));

// logger
Scripts.Add(new YuiScript(YuiScriptType.Logger));
Styles.Add(new YuiCss(YuiCssType.Logger));

// overloaded add method for normal, non YUI Script
Scripts.Add("~/lib/js/ui/dashboard.js");

As you can see, the collection of script and stylesheet controls are simply add to the aspx page's header in the OnPreRender event. This means that you can investigate and manipulate the set of scripts or styles in a simple manner, removing some, adding more etc, right up until the page is rendered, like in the following example:

if (!Scripts.Contains("~/lib/js/ui/dashboard.js"))
{
    Scripts.Add("~/lib/js/ui/dashboard.js");
    Scripts.Add("alert( 'wooo!' );", false);
    Scripts.RemoveAt(3);
}

You can also see in the last example, an overload of the "Add" method to add a script that dosen't have an external source i.e. the "alert(...);" statement.

I feel this method has more control, and prefer it to the default Page.RegisterClientScript() and the ScriptManager, although they both have their pros and cons.

When their next release comes out (current release was 2.2.0 at the time of writing), you should be able to add a key to your web.config's AppSettings like so and your application will use the specified version, provided they don't break with their naming conventions:

<add key="YUI.Version" value="2.2.1" />

Download the sample project
The sample project can be downloaded here. It contains all the necessary files to compile the library, including the dependent TextHelper utilities and base classes for the Script and Stylesheet (and collections) from our internal Singular library.

An improvement on this set of files might be to add a setting to serve the files from a local server location instead of the Yahoo! servers. This would help when developing locally, offline, intranet, or wanting to step through the files while debugging - like I said earlier, the shared files are minified, which dosen't make for very readable code ;)

One final note. The sample library was whacked together pretty quick and contains a couple of less-than-implemented sections: Two of the CSS locations for YUI don't seem to follow a consistent naming convention and have been omitted from the implementation. A better solution than the given samples would be to use a custom Attribute on each of the YuiScriptType and YuiCssType enumerations (or at least the ones that don't fit in with convention easily) to specify a custom location of the corresponding file.

Read more...

Text Helper Utility Part 2: Separation of cased words

Following yesterday's TextHelper.Coalesce post, I'd like to share another useful method for separating cased words i.e. PascalCase or camelCase.

There are a few reasons you might want to do this. It's common place today to use it in Javascript for dealing to CSS styles and the like. The inspiration behind this one was to be able to display the members of an enumeration in a meaningful way to the user e.g. using Enum.GetNames to bind possible values to a drop down list.

Consider the following enumeration:

public enum MyEnum
{
    Pending,
    Active,
    SaveForLater
}

When using Enum.GetNames(typeof(MyEnum)), the first two members are great, but the last member, SaveForLater, just doesn't look right when it comes to UI.

The following code would yield the string "Save For Later".

TextHelper.Separate(MyEnum.SaveForLater.ToString());

Enter TextHelper.Separate().

This method searches a given string prefixing a separator string when it finds an uppercase character. It also considers two uppercase characters in a row as an acronym and only appends the separator when the preceding character is lowercase.

To create the separate method, I compared a version done with regular expressions to the implementation below, which the non-regex version out-performed the regex by a factor of 11. So here's the code, again its simple, but extremely helpful when you need it.

public static class TextHelper
{
    public static string Separate(string casedWord, string separator)
    {
        StringBuilder result = new StringBuilder();
        for (int i = 0, length = casedWord.Length; i < length; i++)
        {
            if (i > 0 && i < length - 1 
                && char.IsUpper(casedWord[i]) 
                && !char.IsUpper(casedWord[i - 1]))
            {
                result.Append(separator);
            }
            result.Append(casedWord[i]);
        }
        return result.ToString();
    }

    public static string Separate(string casedWord)
    {
        return Seperate(casedWord, " ");
    }

    public static string Hyphenate(string casedWord)
    {
        return Separate(casedWord, "-");
    }

    public static string ApplySpaces(string casedWord)
    {
        return Separate(casedWord, " ");
    }
}

You'll also notice the convenience Hyphenate method which is there for your, erm, convenience :)

Read more...

Text Helper Utility Part 1: C# Coalesce

I thought that I should start with something simple, yet useful, to get the blogging juices flowing. So I'm going to write about some of the utility and helper classes I deal with on a day to day basis; The TextHelper.

TextHelper is static helper class containing useful methods for dealing with text and strings.

Existing language functionality:

The first method, and the one I use the most, is a spin off of the Transact-SQL COALESCE function. It adheres to the same principle as the SQL version in that it takes a variable number of arguments, and returns the first non-null, and in our case non-empty, argument. The T-SQL version is used along the lines of:

COALESCE([Col0], [Col1], 'None')

Since C# 2.0, we've also had the coalesce operator; a very handy operator, which can save a lot of if ... else statements. It is used to return the first object that is not null like so:

MyObject a = null; 
MyObject b = new MyObject(); 
MyObject c = a ?? b;`

In the example above, b is the first non-null argument, and is assigned to the variable c.

Why another Coalesce method?

The difference between the aforementioned two methods and the TextHelper.Coalesce method is that they only deal with null values, but we often want null and empty to be considered the same when dealing with User Interfaces. Consider the following example of getting a contact number to display.

string phone = TextHelper.Coalesce(customer.Phone, customer.Mobile, "None Avaialble");

Now when the customer has a empty phone number, the mobile number is returned, and if no mobile number is specified, "None Available" is used as an indicator.

Source Code:

Here's the code extract from the text helper class.

public static class TextHelper
{
    public static string Coalesce(params string[] args)
    {
        string value = string.Empty;
        foreach (string arg in args)
        {
            if (!string.IsNullOrEmpty(arg))
            {
                value = arg;
                break;
            }
        }
        return value;
    }
}

It's an extremely simple method and simply helps cut down on writing more lines of code than are necessary.

It also makes dealing with configuration "AppSetting" a little simpler too e.g.

string setting = TextHelper.Coalesce(ConfigurationManager.AppSettings["MyAppSettingKey"], "My Default Value");

What's Next?

Next time I'll be adding another simple method from the TextHelper class that separates cased words. Handy for displaying PascalCased enum strings and the like.

Read more...

I'm your host, Dave Transom

It's been talked about for a long time, although only amongst colleagues and friends, but I finally have put some time into starting a blog. So here it is, my first blog post ever, that is if you ignore the blogesque style personal websites I started out with in the nineties, before 'blogging' came to, erm, fruition?

Who am I?

I've got to admit, I'm a nerd - I love programming, it's my profession and a hobby too, and it is maybe the reason this blog hasn't happened sooner. But it is also the reason this blog is now here. It may not be a healthy choice of hobby, considering my career, but we're not here to discuss that! My name is Dave, and I'm a codeaholic.

I'm also director of Singular Limited, which is where we spend our time working on online stores, content management systems and web applications in general (or is that not-so-general?).

What's my plan?

Now that you know who I am, sort of, I can say that I find or discover or refine some interesting concepts and ideas to get the job done better (or with more style) and I'd very much like to share some of that with you.

I mainly plan to write about web development, specifically C#, ASP.NET, SQL Server and Javascript, but it won't be limited to that, there's Yahoo! UI Library, Jack Slocum's yui-ext, Script.aculo.us, Prototype and of course ASP.NET AJAX . I'll be sharing ideas and inviting feedback. I plan to release source code and helper utilities here too.

Some of the content is going to be simple; Handy tips that you may or may not know about. Some of it is going to be in-depth, elaborating over concepts and ideas. And some of it is going to be coool, at least I hope you'll think so. One of those cool things is the "Smeild"! Interested? Well I'll post about that in the near future :)

Where does the influence come from?

These are just a few (The real list is a lot bigger) of the people I find make my life easier, whether it be code ideas, insight, putting things into perspective, not to mention keeping up a sense of humour. Jon Galloway, Scott Guthrie, Jon Skeet, Milan Negovan, Phil Haack and Jeff Atwood are a few people I read regularly. Keep up the great work guys.

Read more...