Tuesday, November 2, 2010

New Home

A new home has been found for my tech blog. Please visit http://weblogs.asp.net/kon.

Monday, August 23, 2010

Client-side Data Binding with jQuery Templates

Client-side data binding via templates is nothing new.  But as with all things jQuery, jQuery Templates makes it easier - more flexibility and options with less code.  I do believe that this jQuery plug-in is Microsoft's first contribution to jQuery, and it's a yummy one.  Here's a small example that shows how to bind user data to a grid:

First, define the grid:
<table id="userTable">
    <thead>
        <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Email</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

Then define the template for each grid row:
<script id="tmpl_userList" type="text/html">
    <tr class="${alternate(this.data, this.dataSource)}">
        <td>${FirstName}</td>
        <td>${LastName}</td>
        <td>${Email}</td>
    </tr>
</script>
Notice that the class attribute's value is set via javascript function that takes two arguments: the data item (for this particular grid row), and the complete data source, which is a custom parameter being passed into the template (more on that later).

Alright, we are now ready to retrieve our data and bind.

Let's provide some data from the server:
[HttpGet]
public JsonResult GetUsers()
{
    JsonResult result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet };

    List<User> users = new List<User>();

    users.Add(new User
    {
        ID = 1,
        FirstName = "Jennifer",
        LastName = "Jones",
        Email = "test1@test.com"
    });

    users.Add(new User
    {
        ID = 2,
        FirstName = "Jason",
        LastName = "Johnson",
        Email = "test2@test.com"
    });

    users.Add(new User
    {
        ID = 3,
        FirstName = "Jerry",
        LastName = "Jones",
        Email = "test3@test.com"
    });

    result.Data = new JsonResultData { Value = users };

    return result;
}

Now let's call GetUsers() via an Ajax call and bind the returned data to our grid/table:
$.ajax({
    url: 'Home/GetUsers',
    success: function (response) {
        if (response.Success) {
            var data = response.Value;

            // Use template called tmpl_userList 
            // dataSource is a custom parameter we pass into the template.
            $.tmpl('#tmpl_userList', data, { dataSource: data })
                // Inject data into table userGrid
                .appendTo($('#userGrid')
                // Define event handlers for each row
                .click(function () {
                    var item = $.tmplItem(this);
                    alert(item.data.FirstName + ' ' + item.data.LastName + ' says, "Hi!"');
                })
                // Toggle row color
                .hover(    
                    function () {
                        $(this).addClass('userRowSelected');
                    },
                    function () {
                        $(this).removeClass('userRowSelected');
                    }
                );


        }
    }
});

Background colors used for alternating and selected grid rows:
.userRowAlt
{
    background-color: #F7F8E0;
}

.userRowSelected
{
    background-color: #F2F2F2;
}

And our resulting grid:
grid data bound on the client side via jQuery template

If we examine the rendered HTML, we'll find that the template's markup basically got injected into the <tbody> content:

<table id="Table1">
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr class="userRow">
      <td>Jennifer</td>
      <td>Jones</td>
      <td>test1@test.com</td>
    </tr>
    <tr class="userRow userRowAlt">
      <td>Jason</td>
      <td>Johnson</td>
      <td>test2@test.com</td>
    </tr>
    <tr class="userRow">
      <td>Jerry</td>
      <td>Jones</td>
      <td>test3@test.com</td>
    </tr>
  </tbody>
</table>

And that's it really. Simple, clean, fun!

You can download the complete, fully functional solution here. The solution code is organized slightly differently, with most of the client-side script located inside the .js include. This way you can also see how the HTML markup, templates and script implementation (including data binding) can be cleanly separated and organized.

UPDATE - 10/06/2010:
This jQuery Templates is now an official jQuery plug-in.

Friday, July 30, 2010

Firefox Slowness with localhost on Vista (or XP with IPv6)

I recently encountered an issue with a web project running locally and VERY slowly loading pages (more specifically images) in Firefox. Thanks to this post by Dan Wahlin, I was able to resolve the problem.  Per his post:
It turns out that the slowness is caused by an IPv6 issue with DNS and can easily be resolved by turning IPv6 support off in Firefox while doing localhost testing.  To make the change, type about:config in the address bar, locate the network.dns.disableIPv6 setting and double-click on it to set it to true.  This does the trick for the Firefox localhost issue on Vista and everything is running fast again.

Tuesday, June 8, 2010

YouTube Deep Linking Inside FBML

There's a cool YouTube API option that let's you jump to any point in the video and start playing from there. For example, to jump 1 minute and 45 seconds into this video:
http://www.youtube.com/watch?v=-HWECQa23Cs
Just append #t=1m45s to the end of the URL:
http://www.youtube.com/watch?v=-HWECQa23Cs#t=1m45s

Now, if you want to do the same thing in your FBML Facebook application, the syntax is slightly different. Let's say you have the following FBML code that embeds a video on a page:
<fb:swf
swfbgcolor="000000" imgstyle="border-width:3px; border-color:white;"
swfsrc='http://www.youtube.com/v/-HWECQa23Cs'
imgsrc='http://img.youtube.com/vi/-HWECQa23Cs/1.jpg' width='340' height='270' />

Now instead of #t=1m45s, add &start=105:
<fb:swf
swfbgcolor="000000" imgstyle="border-width:3px; border-color:white;"
swfsrc='http://www.youtube.com/v/-HWECQa23Cs&start=105'
imgsrc='http://img.youtube.com/vi/-HWECQa23Cs/1.jpg' width='340' height='270' />

Thursday, June 3, 2010

SubSonic and Object-Relational Mapping

I love SubSonic (especially the latest 3.x version with T4 template support) and its ability to map data to model objects/data contracts.  However, I've hit a bit of a snag when it comes to mapping not just the high-level object properties, but also its (complex type) children.

Say for example I have the following classes defined:
[DataContract]
    public class User
    {
        [DataMember]
        public int ID { set; get; }

        [DataMember]
        public Role Role { set; get; }

        [DataMember]
        public Profile Profile { set; get; }

        [DataMember]
        public string UserName { set; get; }

        [DataMember]
        public string Password { set; get; }
    }


    [DataContract]
    public class Role
    {
        [DataMember]
        public int ID { set; get; }

        [DataMember]
        public string Name { set; get; }
    }


    [DataContract]
    public partial class Profile
    {
        [DataMember]
        public int ID { set; get; }

        [DataMember]
        public string FirstName { set; get; }

        [DataMember]
        public string LastName { set; get; }

        [DataMember]
        public string EmailAddress { set; get; }
    }

Then using SubSonic, I can run the following fluent query to hydrate a list of users:
List<User> users = db.Select
    .From<User>()
    .InnerJoin<role>(RolesTable.Role_IDColumn, UsersTable.Role_IDColumn)
    .InnerJoin<profile>(ProfilesTable.Profile_IDColumn, UsersTable.Profile_IDColumn)
    .ExecuteTypedList<User>();

However, the problem is that User's Role and Profile properties will remain null - projection mapping FAIL! Now I've spent quite some time googling around for a possible solution to this, thinking that maybe I'll find a "trick" of some sort to have SubSonic auto-magically hydrate all lower-level properties of my User object, without making a bunch of trips to the database and back to hydrate all properties. But I found nothing.

Ben Scheirman and his SubSonic and Projections blog post to the rescue!

First of, let me work backwards and start with the comments following this blog post. Rob Conery (of SubSonic fame) responded to Ben and suggested using ExecuteSingle(), which should map things appropriately. However, I've tried that as well:

User user = db.Select
    .From<User>()
    .InnerJoin<Role>(RolesTable.Role_IDColumn, UsersTable.Role_IDColumn)
    .InnerJoin<Profile>(ProfilesTable.Profile_IDColumn, UsersTable.Profile_IDColumn)
    .ExecuteSingle<User>();

And again, User's Role and Profile properties remained null, while all other simple type properties got set appropriately. Sadly, SubSonic alone couldn't hydrate all my object's children without some assistance.

So, I moved forward with Ben's suggested solution, and it worked beautifully (with some minor tweaks)!

First, define a custom attribute class:
    [AttributeUsage(AttributeTargets.Property)]
    internal class MapToColumnAttribute : Attribute
    {
        private readonly string _columnName;

        protected internal MapToColumnAttribute(string columnName)
        {
            _columnName = columnName;
        }

        protected internal string ColumnName
        {
            get { return _columnName; }
        }
    }

Then, define a projection mapper class, which will do all the leg work for you:
internal class ProjectionMapper
    {
        protected internal T Map<T>(IDataReader dr) where T : new()
        {
            Type type = typeof(T);
            T target = new T();
            foreach (PropertyInfo property in type.GetProperties())
            {
                foreach (MapToColumnAttribute attr in property.GetCustomAttributes(typeof(MapToColumnAttribute), true))
                {
                    object value = dr[attr.ColumnName];

                    if (!(value is DBNull))
                    {
                        property.SetValue(target, value, null);
                    }
                }
            }

            return target;
        }
    }

You'll notice there's a slight difference between this definition and the one in Ben's blog. First of all, he's referencing some ReflectionUtil, which I don't have and wasn't sure what it was. So I simply replaced the ReflectionUtil.GetAttributes() call with property.GetCustomAttributes(). Also, I added a DBNull check of the value - better safe than sorry.

Next, you must decorate your objects' properties with the new MapToColumn attribute, to map the properties to the appropriate columns (their names) returned by the database call:
[DataContract]
    public class User
    {
        [MapToColumn("ID")]
        [DataMember]
        public int ID { set; get; }

        [DataMember]
        public Role Role { set; get; }

        [DataMember]
        public Profile Profile { set; get; }

        [MapToColumn("UserName")]
        [DataMember]
        public string UserName { set; get; }

        [MapToColumn("Password")]
        [DataMember]
        public string Password { set; get; }
    }


    [DataContract]
    public class Role
    {
        [MapToColumn("ID")]
        [DataMember]
        public int ID { set; get; }

        [MapToColumn("Name")]
        [DataMember]
        public string Name { set; get; }
    }


    [DataContract]
    public partial class Profile
    {
        [MapToColumn("ID")]
        [DataMember]
        public int ID { set; get; }

        [MapToColumn("FirstName")]
        [DataMember]
        public string FirstName { set; get; }

        [MapToColumn("LastName")]
        [DataMember]
        public string LastName { set; get; }

        [MapToColumn("EmailAddress")]
        [DataMember]
        public string EmailAddress { set; get; }
    }

And finally, let's use this bad boy:
List<User> users = new List<User>();
User user = null;

SqlQuery query = db.Select
    .From<User>()
    .InnerJoin<Role>(UsersTable.Role_IDColumn, RolesTable.IDColumn)
    .InnerJoin<Profile>(UsersTable.Profile_IDColumn, ProfilesTable.IDColumn);

ProjectionMapper mapper = new ProjectionMapper();
using (IDataReader dr = query.ExecuteReader())
{
    while (dr.Read())
    {
        user = mapper.Map<User>(dr);
        user.Role = mapper.Map<Role>(dr);
        user.Profile = mapper.Map<Profile>(dr);

        users.Add(user);
    }
}

The solution is clean and relatively efficient; this makes Kon a happy boy. Again, I must give most of the credit to Ben Scheirman for his help.

Saturday, May 29, 2010

C# Extension Method Bummer

I love extension methods, which were introduced in .NET 3.5 Framework.  While trying to avoid extending everything and its grandmother, I find them very useful for very common tasks like special ToString() formatting or basic array manipulation (adding an element to an already full array).  But I was pretty disappointed to find an ugly limitation of extension methods, specifically in C#.

Let's say for example you want to create an extension method that adds an item to an array of objects while dynamically growing said array.  Note:  Sure we can do these things easily with ArrayLists or any other type of generic lists.  But say you're stuck with working with simple arrays... just go with me here.

So consider the following extension method:
public static void Add<T>(this T[] source, T newItem)
{
    // Create a new temporary array that's larger than the original
    T[] tmp = new T[source.Length + 1];

    // Copy contents of source array to temporary array
    source.CopyTo(tmp, 0);

    // Assign new item to the temporary array
    tmp[tmp.Length] = newItem;

    // Set original source to the newly grown array
    source = tmp;
}
And then you can simply add an item to an array with a single line of code:
user[] users = new user[0];
users.Add(new user());

Wouldn't it be nice if it were that simple?   ...and working?  Unfortunately, that is not the case with C#.  Remember that in C# objects are passed by value, not reference.  So the fact that we're setting source to tmp at the end of the extension method bares no impact whatsoever on the original source array outside of this method's scope.  This is one of those very rare times I say, "What the hell?!  I'd be better off doing this in VB!"

You also can't use ref keyword to pass this instance into the extension method by reference, because you're not really supplying that parameter to the method when calling it.  So there's nothing to put ref in front of.

So one alternative is to just return the new array:
public static T[] Add<T>(this T[] source, T newItem)
{
    // Create a new temporary array that's larger than the original
    T[] tmp = new T[source.Length + 1];

    // Copy contents of source array to temporary array
    source.CopyTo(tmp, 0);

    // Assign new item to the temporary array
    tmp[tmp.Length] = newItem;

    // Return the newly grown array
    return tmp;
}

But that's ugly, because now you have to assign the return value to the variable you just called a method on:
user[] users = new user[0];
users = users.Add(new user());

And that just gives me the willies.  It gets the job done, but... ugh..   I sure would have preferred to be able to alter the original object within the extension method - that way seems a lot cleaner to me.  What a bummer!

Friday, May 21, 2010