Monday, July 4, 2011

jQuery tmpl page size vs. asp.net server control page size.

My previous post went over how to do a simple data bind using client side data binding with the jQuery tmpl plugin as opposed to data source objects and grid server controls that are often used with asp.net.  I think it's better way to go when possible.  One of the benefits of the tmpl plugin is that the page size is much smaller and you get to do away with all that view state.

I created a new project that does the same thing as the project from my previous post, only it uses asp.net UI server controls as well as the script manager and update panel controls.  You can download the new project here.

Figures 1,2 and 3 are screen shots of  web page properties from the new project along with a description of what you are looking at.  The main thing we care about is page size.


Figure 1

Have a look at figure 1.  This is just a plain asp.net page that has no ajax on it.  Just regular post backs.  Notice the page size is 4,766 bytes.















Figure 2

In figure 2 the same project, but we added a script manager tag which is required for a .net page that's going to use the ajax control tool kit or any of the ajax controls like the update panel.  Notice the size has jumped to 6,433 bytes and we haven't even added any update panels yet.













Figure 3

Here in figure three we have added the update panel, so that now our application mimics the jQuery application from the previous post.  Notice the size of the page is now 6,562 bytes.















Figure 4

Now in figure 4 I'm running the jQuery tmpl demo application from the previous post.  Notice the page size is 2,037 bytes.  That's less than 1/3 the size of the server control version using the script manager and the update panel.  No big deal you say?  In the world if 3G, it is a big deal.  On a network with lots of traffic, it is a big deal.   I think it's a more elegant solution.












Note: The property pages are from Internet Explorer 8, but the type is Chrome HTML Document because Chrome is my default browser.

Saturday, July 2, 2011

jQuery tmpl plugin example for ASP.Net

Originally I was going to call this post, "Look Ma!  No view state!" but view state isn't really what I to talk about it.  This example will have no view state, but that's a side benefit.

What I want to talk about is client side data binding with jQuery.  The jQuery tmpl plugin has been documented in a number of places and I'm not going to show anything new here.  This post is intended to be a simple example for people still using data grids and heavy .Net server controls.  This example won't use any server controls.  We won't have a form tag and there will be no code behind.  Let's get to it.

Step 1: Create a web service

Here's our simple web service.  I called it "wsPlayers".  It has one method and returns a list of custom objects based on a simple NBAPlayer class.  Be sure to uncomment the line...

[System.Web.Script.Services.ScriptService]


...so that the web methods in the service can be called from client side JavaScript. We will also want to add a reference to the Script.Services namespace at the top of the file...

using System.Web.Script.Services;

...so that we can change the format of our web method to JSON (it's XML by default).

So here is the full  text of our web service method:


Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services; //Have to add this namespace for the ResponseFormat on the webmethod).
   
namespace tmplDemo
{
 /// <summary>
 /// Summary description for wsPlayers
 /// </summary>
 [WebService(Namespace = "http://tmplDemo/")]
 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
 [System.ComponentModel.ToolboxItem(false)]
 // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
 [System.Web.Script.Services.ScriptService]
 public class wsContacts : System.Web.Services.WebService
 {

  [WebMethod]
  //***The ResponseFormat has to be added to the method, not the WebService Class (above).
  [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
  public List<NBAPlayer> GetPlayers(int paramMinChampionships)
  {
   List<NBAPlayer> tempPlayers=new List<NBAPlayer>();
   
   NBAPlayer temp1 = new NBAPlayer("Nowitzki","Dirk",1);
   NBAPlayer temp2 = new NBAPlayer("James", "LeBron", 0);
   NBAPlayer temp3 = new NBAPlayer("Wade", "Dywane", 1);
   NBAPlayer temp4 = new NBAPlayer("Bryant", "Kobe", 5);
   NBAPlayer temp5 = new NBAPlayer("Paul", "Chris", 0);
   
   tempPlayers.Add(temp1);
   tempPlayers.Add(temp2);
   tempPlayers.Add(temp3);
   tempPlayers.Add(temp4);
   tempPlayers.Add(temp5);

   return (from p in tempPlayers 
     where p.championships>=paramMinChampionships 
     orderby p.lastname,p.firstname
     select p).ToList<NBAPlayer>();
  }
 }
 public class NBAPlayer{
   public NBAPlayer(string lname,string fname,int chmps){
   lastname=lname;
   firstname=fname;
   championships=chmps;
  }

  public NBAPlayer()
  {

  }

  public string lastname { get; set; }
  public string firstname { get; set; }
  public int championships { get; set; }
 }
}

As you can see from the code, the web service has a method called GetPlayers and it accepts one parameter of type int called paramMinChampionships.  It then returns a list of type NBAPlayer where each NBAPlayer object has a championship property equal to or greater than the paramMinChampionships.

Now, I've made a custom class and hard coded a few elements for the example but this is where you'd put your database calls or Linq objects and build your return set that way.  We're done with the web service.

Step 2: Download jQuery files.


Create a directory in your project called jQuery.  Download these two jQuery files:


Add these files to the jQuery directory you made at the beginning of this step.

Step 3: Create a default.aspx page.




Add a new file called default.aspx.  Once you've done that, your solution explorer should look something like the image at left.







Now the fun part.  First we're going to create some javascript that will do our Ajax call for us:

<script type="text/javascript">
        function GetPlayers() {
            $.ajax({
                url: "wsPlayers.asmx/GetPlayers",
                dataType: "json",
                type: "POST",
                contentType: "application/json; charset=utf-8",
                data: ("{paramMinChampionships: " + $("#selChamps").val() + "}"),
                error: function (err) {
                    alert("Error:" + err.responseText);
                },
                success: function (results) { OnComplete(results.d) }

            });
        }

        function OnComplete(results) {
            $("#tbodyPlayers").empty();  //We want to clear the body of the table first.
            $("#playerDataTemplate").tmpl(results).appendTo("#tbodyPlayers");
        }

    </script>


If that doesn't make sense, then stop right here and read about the jQuery Ajax method.  What we're doing is calling our web service and passing it a numeric value so that it will give us back our list of players.  Before we do that lets add the rest of the HTML to our default.aspx page.

We want a select element that looks like this:

Players with at least 
    <select id="selChamps"> 
        <option value="0">0</option> 
        <option value="1">1</option> 
        <option value="2">2</option> 
        <option value="3">3</option> 
    </select> 
    championships.

We'll want a button to fire off our ajax web service call:

<button id="btnSubmit" onclick="GetPlayers();" >Submit</button>

We'll also want a table to display our data:

<table border="1"> 
        <thead> 
            <tr> 
                <td>First Name</td> 
                <td>Last Name</td> 
                <td>Championships</td> 
                <td>Bing</td> 
            </tr> 
        </thead> 
        <tbody id="tbodyPlayers"> 
         
        </tbody> 
    </table>

Lastly, and most importantly, we add the data template:

<script id="playerDataTemplate" type="text/x-jquery-tmpl"> 
    <tr> 
        <td>${firstname}</td> 
        <td>${lastname}</td> 
        {{if championships>0}} 
        <td align="center"><span style="color:green;font-weight:bold;">${championships}</span></td> 
        {{else}} 
        <td align="center">${championships}</td> 
        {{/if}} 
        <td><a target="_blank" href="http://www.bing.com/search?q=${firstname}+${lastname}">search</a></td> 
    </tr> 
</script>


That's right, we're putting HTML markup directly inside our <script> tag in the example above.  Notice that the type is type="text/x-jquery-tmpl" and not type="text/javascript". This is a different kind of script that works with the tmpl plugin. The magic is in the OnComplete method and the data template we created.  Pay special attention to this line of JavaScript code:

$("#playerDataTemplate").tmpl(results).appendTo("#tbodyPlayers");

What this means is, we're going to take the value of results, which is the JSON object that contains our list of player data, pass it to the tmpl function of the playerDataTemplate selector and append the output to the
tbodyPlayers selector. The playerDataTemplate will apply what's inside for each element in the results variable. As you can see, by using the {} brackets we can drop the values of the properties whereever we want.  We can apply conditional if/else and we can put our property values inside HTML markup. And we can do it all without asp.net server controls or a code behind.  Well,we do have a code behind of sorts but that is encapsulated in the web service.  So if we have an iPhone app that wants to call our web service, no problem.  Windows forms wants to use it?  No problem.  Another thing about this approach is that we are getting away from all the custom .net control styling markup and back to straight up css.  Now when a designer looks at our source and wants to make some tweaks, they don't see a buch of <asp:textbox id="txtFirstName" runat="server" text="Johnny" />.  The see regular HTML that they should be able to update without breaking anything.

Another advantage to this approach is that we are doing an Ajax call but since we're not using an asp.net update panel and things like that, we're only sending and receiving the JSON objects.  That's a really light payload compared to all the view state stuff we'd get if we used update panels.  We also aren't using an asp.net script manager, we're just referencing our jQuery libraries normally so we don't have that overhead either.  I may do a follow up post to this one where I use update panels, script managers and a datagrid to show the difference in page size and network traffic.  It makes a huge difference.

So, that's the tmpl plugin for jQuery and that's why I love it.  If you want to play around with this project yourself, you can download the whole thing here.

Thursday, April 7, 2011

Web Service Minutiae

Sometimes, as part of a web project, I'll make a web service that will be called by a front end .aspx page elsewhere in the project.  Inevitably, I will forget to do two things:

One, I'll forget to uncomment the script service line above the web method, even though Visual Studio puts a comment above it that says the following:

'To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
 '<System.Web.Script.Services.ScriptService()> _
And two, I'll forget to set the InlineScript property of the service reference to true.  

Then I'll trouble shoot for an hour before I remember, oh yeah, I have to do those two things.  Hopefully by writing this on my blog, I'll remember.  Anyway, those to two tidbits are things that I forgot, but I did know at one time.  This week I learned some new things regarding web services.  I'm sure many developers out there will say, "well duh...I can't believe you didn't know that!  Dunce!"  In response to such barbs, I will quote Clark Gable in Gone With the Wind, "I apologize again for all my short comings."  Moving on...

Here are the two, new, things I learn about web services.  One, you can change the format of the SOAP data that gets passed back and forth from the verbose (but useful) XML format to the more concise Json format.   Did you know that?  I sure didn't.  You just change the property in the web method:

<WebMethod()> _
    <ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
    Public Function DoSomething() ...

Please note that the above code snippet assumes the import of the System.Web.Script.Services namespace.  I hate it when demo code doesn't include what namespaces are involved.

The second thing I learned is that there is a size limit on how big the Json object can be.  I was all happy until I quit getting results back because I knew there were lots of the results that were coming back and that was the problem.  You can set it manually in the web.config, like this:

<jsonSerialization maxJsonLength="Big ol' number"/>

...but I wouldn't recommend that.  Why?  Because the whole point of Json is to have light weight markup text so you can pass data around web services with less bandwidth.  If your Json is so big that the default size of the object isn't big enough to handle it, then maybe there's just too much data in there and it needs to be broken up some other way.  But hey, do what you want.  Pass multi gig Json objects around, set the IIS timeout to 120 minutes and put all your asp.net applications in their own app pools.  See what happens.

G'night.

Monday, January 24, 2011

B is for Backup

     In the old days of the 20th century, computer users relied on floppy disks to move information from one computer to another.  Pre-web, pre-broadband, pre-dialup...it was all floppy disks.  Now, it really wasn't as bad as it sounds because we didn't have that much information to move around.  It was conceivable that you would do all of your computing on one computer.  That is until you got another machine and moved all your stuff over to the smokin' hot 486.  Again, it didn't matter because there wasn't that much stuff to move.  A floppy disk might not have a enough space on it to save one mp3 track but you could still store lots of text and that's mostly what we had.  You made a backup copy of all your papers or saved games of Flight Simulator and that was it.  Everything else was loaded from stacks of floppy disks or maybe a dual speed CD-Rom.  Not so any more.

     Now we have lots and lots more data.  My daughter is not even a year old yet but I bet she's had more pictures taken of her than I had in the first ten years of my existence.  They are all digital.  In addition to those photos I have movies, music, family videos, gobs and gobs of photos, lots of source code and database scripts.  Lots of people have this problem and they don't have a backup of that data because...it's impossible.  Households can easily have a 1 terabyte of data spread across phones, laptops, desktops, digital cameras and mp3 players.  It would take 728,177 floppy disks to back up one terabyte.  And you'd have to label them too...

     Now imagine that your hard drive crashed(they all have a MTBF rating), or your laptop got stolen.  What then?  All that music, all those movies you bought on iTunes are gone.  All those photos...

     Here's what I recommend.

  1. Get a big external hard drive.  I use a two terabyte external drive from Western Digital.  You can buy it off Amazon for a little over $100.  Here's the link.
    1. Make a folder on it called "Backup".
    2. Under that you can make folders for music, videos, photos, office documents...whatever you want.
    3. Put everything that's important in there.  
    4. Point your iTunes library to that location if you have one.
    5. I suggest connecting the external drive to a desktop or some machine that's usually on or at the very least, doesn't move around much.
  2. Get an account with an online backup company.  There are several out there.  I use Mozy.com.  For $4.95/month you get unlimited backups.
    1. After you've downloaded the Mozy client, you can set it to backup certain directories.   Set it to backup the "Backup" directory on your big external drive.  It'll take a long time (as in days) to do the first backup, but once that first one is done, you are set.  Leave your computer on over night and it will backup all the new things you add.
    2. I recommend Mozy because on two different occasions I've had hardware crashes and I did not lose a thing.  It took a while to copy all that stuff back down to a new machine, but that's way better than losing everything.
  3. For Office type files or things that are mostly text, I suggest using a free account from DropBox in addition to having an online backup.  Dropbox is incredibly convenient and it serves as a quick and easy way to keep things backed up and accessible.  
         You may be saying to yourself, "Jon, I'm not going to spend $100 for a big hard drive and $60 a year for online backups."  Well, okay, but think about this. If you lost all your data, how much would you be willing to pay to get it back?  Sure it's another bill to pay.  I don't like adding bills to my monthly payment list, but it provides peace of mind.  I sound like an insurance salesperson but that's exactly what this is. Except this is insurance you will need because, while your house might not flood or burn down, your hard drive will crash one day.  That day might bring a momentary inconvenience or a catastrophe.  And by the way, if you are a freelancer of any kind, you have to have an offsite backup.  If people are paying you to produce something,  you can't just turn around and say you lost all the work because your Mac Book crashed and you don't have a backup.  It's a cost of doing business.

    ...

         So that's my online backup rant.  Now let's talk about saving a little money.  Are you still using the anti-virus software that came with your computer?  Norton Anti-Virus or MacAfee or something like that?  Well, those things expire and if you don't pay up each year, you quit getting the latest virus signatures which is what allows anti-virus software to protect your machine.  Without the latest updates, you're are not getting any protection.  Those full disk scans that slow your computer down are all for naught because they won't know if a new virus is there or not.  

         In the past I have recommended the free anti-virus software from AVG.  I still think they provide a great product, but they really want you to sign up for their pay service.  Every so often you have to download a new client and install and it's a headache.  It's easy to click ignore or to mistake it for an annoying popup from some web page and you can wind up back in the same boat.  I have a new recommendation.  It's only for the Microsoft platform but I really like it.  It'll work with anything from XP service pack 2 all the way up to  Windows 7 Ultimate 64-bit.  It's called Microsoft Security Essentials.  Download it, install it and uninstall all that useless, out of date, anti-virus software that's just taking up system resources.

    ...

         Lastly, if you hate the bloat ware that is Adobe Acrobat Reader but you still need to be able to read PDF files, then download Expert PDF Reader from Visagesoft.  Great PDF viewer, nowhere near the headaches of Adobe Acrobat REader.  It's free.