Adding "Select All" functionality to Facebook Invites

Disclaimer: At the time this article was written, this code was verified to work on Chrome 15.x, Firefox 5.x, and IE 8.x). Facebook, however, could change their markup at any time, rendering unexpected results in any browser.  Use at your own risk.

One of the pains of maintaining a Facebook page becomes evident when you want to send invitations to all of your friends.   Instead of providing a "Select All" button, you are required to click on every checkbox for every person that you would like to have added to the list. 

invitepic

For pages that have 1,000 or more friends, this process is extremely cumbersome. 

The solution is to use JavaScript to select all of the names for you!

In order to do this, we need to:

  1. Find out the name that is being used for each checkbox element (hopefully they have a consistent name for all checkboxes... otherwise we'll need to use more general functions to traverse the DOM).
  2. Create some JavaScript code that selects all of the checkboxes (by typing in some executable JavaScript into the Location/Address Bar).

Sure, this may seem like as much work as clicking each checkbox, but once we've determined what JavaScript will "select all" invitees, we can simply cut and paste this code for all future invites... at least until Facebook changes their markup.

 

Step 1: Determine the Checkbox Name

There are lots of tools that let you inspect the DOM of a web page.  In this case, I'm using the built in inspector that comes free with the Chrome browser.  I simply right click on the checkbox and select "Inspect Element."

elementname

We're in luck!  After inspecting several checkboxes, I was able to see that there is a consistent name being used: "checkableitems[]."  We'll use this name with the DOM API to get a collection of all the checkboxes on the page.

 

Step 2:  Create our "Select All" JavaScript

Our code is going to be very simple... retrieve a collection of all the checkboxes on this page, iterate through that collection and programmatically add a checkmark. 

To retrieve the collection of checkboxes, we'll use a DOM method on the "document" object: "getElementsByName()":

   1:  var invitees = document.getElementsByName("checkableitems[]");


Next we need to iterate through each of the objects in this collection.  For this we'll use the "For" loop.   I had originally used a "ForEach" loop in this example, but switched it to this for compatibility with IE.

   1:  for( i = 0; i < invitees.length; i++ )
   2:  {
   3:      // ...
   4:  }
 

The object we're referencing from the collection, an HTMLInputElement, includes a "checked" property.  Normally, setting this to a value of "true" (resulting in a checkmark), would be sufficient...

   1:  invitees[i].checked = true;


... and although that will cause each person to become checked, my testing has shown that it doesn't affect which invitees have actually been selected.  So, let's try another option... perhaps there is some event handling that is kicked off when a check box is clicked.  Rather than just calling "click" on the element, let's double check that the type of element we're clicking is a checkbox (I'd hate to accidentally click a button that says "remove friends").

   1:  if( invitees[i].type == "checkbox" )
   2:  {
   3:      invitees[i].click();
   4:  }


Putting this all together:

   1:  var invitees = document.getElementsByName( "checkableitems[]" );
   2:  for( i = 0; i < invitees.length; i++ )
   3:  {
   4:      if( invitees[i].type == "checkbox" )
   5:      {
   6:          invitees[i].click();
   7:      }
   8:  }


Let's tighten this up with shorter variable names and no unnecessary white space (something I wouldn't normally advocate; verbose and meaningful code is preferable to that which is compact and obscure.  Nevertheless, the goal here is to have a single line of code that we can cut and paste into the location/address bar):

   1: a=document.getElementsByName("checkableitems[]");for(i=0;i<a.length;i++){if(a[i].type=="checkbox")a[i].click();}

 

The Solution:

Facebook doesn't load all of your friends at once.  Instead, it loads more people as you continue to scroll down the list of names.  So the first thing you need to do is open up the "Invite Friends" window, and drag the scroll bar down until you reach the end of your list.  You'll notice the bar sometimes jump a bit as it continues to load names into the window.

scroll

Now to execute the code written above, we simply need to prepend it with the word "javascript:" (note the colon), so the browser executes it as code, rather than treat it like a website url.  I also added a "void(0);" at the end to prevent IE & Firefox from reloading the page (a trick I learned from http://stackoverflow.com/questions/2918776/javascript-in-an-address-bar).

Thus, the actual code to cut and paste into your "Location/Address" bar is:

javascript:a=document.getElementsByName("checkableitems[]");for(i=0;i<a.length;i++){if(a[i].type=="checkbox")a[i].click();}void(0);

Note:  Some browsers will not let you and cut and paste the word "javascript:" into the location/address bar.  Double check to make sure your code starts with "javascript:" before clicking enter (if it's not there, just type it in).  Also, some versions of Firefox won't let you run any javascript commands in the location/address bar.  In that case, under Tools, find the "Scratch Pad", and execute the JavaScript there.

endresult
It may take from several seconds up to a couple of mins to select everyone... 
the longer your list of friends, the longer it'll take to add the checkmarks.

That's it!  From here on out (until Facebook changes their markup), all that we'll have to do is create an invite, scroll down to the end of our list, cut/paste that single line of code, and all of our friends will be selected!


Posted by: Jason Shapiro
Posted on: 11/6/2011 at 9:09 PM
Categories: Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

ASP.NET 4 ClientIDMode Property Explained

There has been some confusion about how to work with this property to your advantage.  With out being to long winded I hope to provide some clarity.

When to change the ClientIDMode of a control?

...if you need to locate specific controls that exist in a repeating data control without capturing events from that control which you are try to reference.  This commonly occurs when you are trying to coordinate user actions to html objects using JavaScript.  

First lets look at the possible values for this property:

AutoID Process used in previous versions ASP.NET  which was prefixing an incrementing value to the control ID
Static Client ID value is set to the value of the ID property
Predictable

Basic Algorithm is either of the following
[parent clientid] + "_" + [ClientIDRowSuffix]
or

[parent clientid] + "_" + incrementing value

Inherit Control inherits the setting of its parent control

For a complete description visit ClientIDMode On MSDN

To demonstrate the affects of each of the property values and how the generated client side ID is affected I will create an web page with several controls:

  1. Using VS 2010 File menu create a new ASP.NET Empty Web Application.
  2. Add a new Web Form
  3. Open the web form
  4. In design view drag and drop two Grid Views onto the design surface making sure they are contained in the default div tag that was provided by the designer.
  5. For both GridViews set the AutoGenerateColumns="false"
  6. We now have two unexciting GridViews that need some data.  Add a new class to the solution.  Name Product and give it two properties (feel free to use the following)
       1: public class Product
       2: {
       3:    public string ProductID{get;set;}
       4:    public string ProductName{get;set;}
       5: }
  7. Open the code behind file for the Web page, for me it is named WebForm1.aspx.cs for me
  8. Create a new method that will be used to populate our GridViews with a list of Products.  (see following code).
       1: protected void Page_Load(object sender, EventArgs e)
       2: {
       3:     LoadProductsToGrids();
       4: }
       5:  
       6: private void LoadProductsToGrids()
       7: {
       8:     List<Product> productList = new List<Product>
       9:     {
      10:         new Product{ProductID="A026",ProductName="Apples"},
      11:         new Product{ProductID="B146",ProductName="Bananas"},
      12:         new Product{ProductID="C276",ProductName="Chiote"},
      13:         new Product{ProductID="D356",ProductName="Drumsticks"},
      14:         new Product{ProductID="E486",ProductName="Elephant Ears"},
      15:         new Product{ProductID="F556",ProductName="Fries"},
      16:         new Product{ProductID="G656",ProductName="Green beans"},
      17:         new Product{ProductID="H756",ProductName="Hay"},
      18:         new Product{ProductID="I856",ProductName="Idaho Potatoes"}
      19:     };
      20:     GridView1.DataSource = productList;
      21:     GridView2.DataSource = productList;
      22:     GridView1.DataBind();
      23:     GridView2.DataBind();
      24: }
  9. To display this data on our web page I will use templated fields because it will easily allow me to demonstrate the affects of the ClientIDMod property.
  10. Open the web page and view the HTML source and add the following templated fields to both of the GridViews
       1: <Columns>
       2:     <asp:TemplateField>
       3:         <HeaderTemplate>Product ID</HeaderTemplate>
       4:         <ItemTemplate ><asp:Label ID="ProductID" runat="server" Text='<%# Bind("ProductID") %>'></asp:Label></ItemTemplate>
       5:     </asp:TemplateField>
       6:     <asp:TemplateField>
       7:         <HeaderTemplate>Product Name</HeaderTemplate>
       8:         <ItemTemplate ><asp:Label ID="ProductName" runat="server" Text='<%# Bind("ProductName") %>'></asp:Label></ItemTemplate>
       9:     </asp:TemplateField>
      10: </Columns>
  11. Now before we run code for two labels contained in the second "GridView2" set the the ClientIDMode to "AutoID"
  12. [Example #1] Running the application you will see two identical grids, but viewing the page source will reveal:
    1. The top grid with the label controls using the default ClientIDMode of Inherit have the control naming pattern ParentContainerID_LabelID_IncrementingValue
    2. The bottom grid with label controls using the default ClientIDMode of AutoID have the control naming patter that was used in prior ASP.NET versions ParentContainerID_ctl+incrementingvalue_IncrementingValue
    3. Inherit_vs_AutoID
  13. [Example#2] Lets change the labels contained in GridView1 to have the ClientIDMode = "Predictable"; Then change the labels in GridView2 to have the ClientIDMode = "Static"
  14. Running the application you will see the following results
    1. The ClientIDMode = "Predictable" behaves as we had seen with the Inherit setting but be careful Inherit will take on its parent setting and could cause some unexpected results when your controls are inside a container such as a Master Page.  So be sure to set your ClientIDMode to predictable if you have dependencies on the control name being ....well...'predictable'
    2. The value of Static, is just like it sounds, this property value causes all iterations of the control to be named the same "ProductID" and "ProductName" respectively.  Regardless of what we do to the containing GridView the labels will continue to repeat the same name.
    3. Predictable_vs_Static
  15. [Example#3] Now we've seen the variations of the ClientIDMode property to see the true value of the property we need to use the ClientIDRowSuffix property that is available to us on the GridView (and some other controls).
    1. On GridView1 set the ClientIDRowSuffix = "ProductID"
    2. On GridView2 set the ClientIDRowSuffix = "ProductID" and ClientIDMode = "Static"
    3. For the labels contained in GridView2 set the ClientIDMode = Predictable
  16. Running the application you will see the following pattern:
    1. For the label controls contained in GridView1 the label IDs have the following pattern: ParentContainerID_LabelID_ProductID
    2. For the controls contained in GridView2 the label IDs have the following pattern: LabelID_ProductID
    3. ClientIDRowSuffix

So you can see that using the ClientIDRowSuffix along with the ClientIDMode you can establish a control ID naming pattern that should support the majority of your needs.

Visual Studio 2010 C# Project Source (ClientIDMode Example)

~Enjoy~


Posted by: Jim Rouse
Posted on: 9/19/2011 at 7:00 AM
Categories: ASP.NET | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

Intertech Struts Training Video | 5 min Intro

Learn more about struts by watching this 5min video...


Posted by: Intertech
Posted on: 9/8/2011 at 3:37 PM
Tags: ,
Categories: Java | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

ASP.NET Chart Drill Down

In this example we will extend the previous pie chart to be a drill down chart, so all of the code and data will be utilizing what had been previously created.  Please feel free to start with code from previous blog (Create ASP.NET 4.0 Pie Chart with Tooltips). 

What are we creating?

A drill down chart is an interactive chart that has clickable or interactive hot spots that will allow us to view more specific information for user selected data. Continuing with our retail theme from the first blog: A department level manager, having been impressed with your pie chart, would like to have a line graph be displayed with more specific sales information for the selected product category.


A moment on User Interface Design

Before we start coding it's important to think about how our application is being used; yes what is the workflow of our targeted end users, will they typically use the mouse or keyboard to navigate within our application. In this case we are being requested to provide a line graph based on a selected value. We do have options to accomplish this task, and depending on the typical workflow of our end users we can quickly determine which option is right for your application.

Two simple options to accomplish this task would be:

1. Use a drop down list control that would allow the user to select the department from the list; great for those who primarily use the keyboard for application navigation (think data entry).

2. Pie graph interactivity, creating clickable graph hot spots allowing the user to click the desired product category and display the corresponding data.

Given the title of this blog you know that I will be using the second option but it is important to know there are several reasons why I would choose the section option.

1. Today's users are expecting more interactivity from their business applications, this includes graphs.

2. In this example, the manager assures me that users will primarily be using a mouse for navigation as these charts will be hosted inside an internal Share Point site.

3. So for the 'mouse-navigators' of the world this means that by using drill-down functionality (as compared to the drop down) will require one less mouse-click for the user to accomplish their desired response (seeing the detailed data). (Alternatively, if my users were primarily using the keyboard for navigation then I most likely wouldn't use a graph drill down for navigation.)


Lets start coding (Extend the existing pie chart)

First we need to extend the existing pie chart to provide data and the event that will allow us to respond to the user's request. An item to note is that utilizing multiple series for a single chart is very helpful in supporting your business rules and typically the easiest option to reference corresponding data values after your graph has been data bound.

  1. Set the PostBackValue for Series1
    • Open the Series Collection Editor by selecting the Pie Chart and clicking the ellipsis for the Series propertySeries Property
    • Select Series1 in the Members panel
    • In the properties panel scroll down and expand the 'MapArea' section
    • Set the PostBackValue to '#VALX' this will set the post back value to the same value as our XValueMember. (most of the chart keywords will work here reference links below)
    • Click ok and save
  2. Add a new series to the chart
    • Our existing pie-chart series holds the department name and total sales. We need a series to retain our department ID so we have a concrete value to request additional information from the database.
    • In the design view select the pie chart
    • In the properties window select the ellipsis for the 'Series' property
    • In the 'Series Collection Editor' dialog click the 'Add' button
    • For the new series set the following properties
      • ChartType = "Pie"
      • Name = "ProductCategoryReference"
      • XValueMember = "ProductCategoryName"
      • YValueMember = "ProductCategoryID"
    • Yours series should look like this:AddSeries
    • Click the 'Ok' button to close
  3. Map Product Category ID to PostBackValue
    • To reference the concrete ID in the series that we created in the previous step we must use some code.
    • Select the chart and add an event handler for the "DataBound" event.
    • Go to the code behind and add the following code
    • The code appends the ProductCatogoryID from the second series to the post back values of the original series
         1: protected void Chart1_DataBound(object sender, EventArgs e)
         2: {
         3:    Chart chart1 = (Chart)sender;
         4:    int dpCount = chart1.Series[0].Points.Count;
         5:    for (int x = 0; x < dpCount; x++)
         6:    {
         7:        DataPoint ptRef = chart1.Series["ProductCategoryReference"].Points[x];
         8:        DataPoint ptTarget = chart1.Series["Series1"].Points[x];
         9:        ptTarget.PostBackValue += string.Format(",{0}", Convert.ToString(ptRef.YValues[0])); ;
        10:    }
        11: }
  4. Add Click event handler to the Chart control

    • Add code to capture our post back values
    • Add a session variable to retain the selected product category id
         1: protected void Chart1_Click(object sender, ImageMapEventArgs e)
         2: {
         3:     string[] postValues = e.PostBackValue.Split(',');
         4:     int productCategoryID = int.Parse(postValues[1]);
         5:     Session["ProductCategoryID"] = productCategoryID;
         6: }
  5. Drag a new SQLDataSource on to the design surface
    • Configure the data source (see my configuration below)
    • Be sure to add the session parameter to the query
         1: <asp:SqlDataSource ID="sqlSalesByProductCategory" runat="server" 
         2:     ConnectionString="<%$ ConnectionStrings:SalesDatabaseConnectionString %>" 
         3:     ProviderName="<%$ ConnectionStrings:SalesDatabaseConnectionString.ProviderName %>"
         4:     SelectCommand="SELECT ProductName, COUNT(P.ProductID) CountOfSales FROM ProductCategory PC INNER JOIN Product P on PC.ProductCategoryID = P.ProductCategoryID INNER JOIN Sale S ON P.ProductID = S.ProductID WHERE PC.ProductCategoryID = @SessionProductCategoryID Group By ProductName">
         5:     <SelectParameters>
         6:         <asp:SessionParameter Name="SessionProductCategoryID" SessionField="ProductCategoryID" DbType="Int32" />
         7:     </SelectParameters>            
         8: </asp:SqlDataSource>
  6. Add our detail graph (Line Graph)
    • From the toolbox drag/drop a new Chart onto the design surface
    • Set the following properties by selecting the smart tag carrot '>' when viewing the chart control on the design surface:
      • Choose Data Source = "sqlSalesByProductCategory"
      • Chart Type= "Column"
      • X Value Member  = "ProductName"
      • Y Value Member = "CountOfSales"barchartproperties
  7. That's it!!
    • Save your work and press F5 to run
    • Clicking an area on the pie chart will cause the bar chart to be populated.

FinishedProduct

Now you may have noticed the ugly post back process that repaints the screen for each click of the pie chart (this is easily solved by using an Ajax Update Panel control) who knows maybe a future blog.

~Happy Charting~

Jim

Chart Control Keywords (MSDN)

Visual Studio 2010 C# Project Source (Chart Drill Down)


Posted by: Jim Rouse
Posted on: 8/15/2011 at 8:40 PM
Tags: ,
Categories: .NET | ASP.NET | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

We're Hiring!!!

Thanks to our loyal customers and the great work our team members are doing for those customers, we are growing. We're looking for top talent to join our award winning team. Our staff get to teach the top firms in the country on the latest technologies or use those same technologies to build great new application for clients.

If you like solving challenging problems with great technology this might be the place for you.

Here are some of the needs we have:

·         Senior Developer/Architect (.Net Silverlight WPF WCF)

·         C# ASP.NET Developer

·         Software Developer (.Net)

·         Software Developer (ASP.Net MVC)

·         Software Developer (C# ASP.NET)

·         Sr. Systems / Software Engineer ( C#.Net )

·         .Net Manufacturing Systems / Solutions Architect

·         C#.Net developer

·         .Net Developer

·         Systems / Solutions Architect (.Net Manufacturing)

·         ASP.Net MVC Developer

·         Senior .Net Silverlight WPF WCF Developer/Architect

·         Sr. C#.Net Systems / Software Engineer

·         Senior Java Developer\Architect

 

For more details on our jobs, click here.

 

You can also apply online or if you find a job that is perfect for a friend, we make it easy for you to send it to them.

 

Let us know if you find one that is perfect for you or if you know someone who may be a great fit.

 

We’re offering a free training certificate to anyone who refers someone that joins our firm.

 

Thanks!

 

 


Create ASP.NET 4.0 Pie Chart with Tooltips

If you?re new to ASP development or if you?re like myself and have developed applications for many years, and do not routinely revisit all of the controls for every .NET release, if you haven't already, I would strongly suggest reviewing Microsoft?s ASP.NET 4.0 charting controls before purchasing a third party charting control package.

If you?re familiar with the charting components of Excel you will find the ASP Charting controls to provide a similar set of chart templates and functionality.  The ASP.NET 4.0 Chart control provides such a rich set of functionality that I would argue that using this control should satisfy the majority of your charting needs.

In this example I will introduce ASP Charting control by showing how quickly you can build a pie chart, associate it to a Sql data source set up the series and display tool-tips.
The basic steps in the is example is:

  1. Create the data model
  2. Create web application
  3. Add a data source
  4. Add chart control
  5. Add chart tooltips

Data Model

As with all charting needs we need to have some data to that will be represented by our chart.  The following diagram shows the data model that I used for this example:

DataModel

The data model consists of a products table where a given product is grouped by a product category.  As each product has been sold there is a corresponding record of that sale in the Sale table.

Web Application

  1. Open Visual Studio
  2. Create a New ASP.NET Empty Web Application
  3. Add a new Web Form (.aspx) page to the project
  4. Open the design view for the web form added in the previous step.

Data Source

  1. With the web form design view visible expand the "Data" section in the tool box
  2. Drag & drop a new Sql Data Source object onto the body of the web form.
  3. In the design view select the Sql Data Source object that was just added and click the carrot that appears then select "Configure Data Source".
  4. Select or create a New Connection string
  5. After defining your connection string click "Next>" 
  6. On the "Configure the Select Statement" screen select the radio button for "Specify a custom SQL statement or stored procedure
  7. On the screen "Define Custom Statements or Stored Procedures" make sure the "Select" tab is selected
  8. Select the radio button for "SQL statement" 
  9. For the data model above use the following SQL statement in the text field:
       1: SELECT PC.ProductCategoryName, PC.ProductCategoryID, SUM(S.Price) TotalSales 
       2: FROM ProductCategory PC 
       3: INNER JOIN Product P on PC.ProductCategoryID = P.ProductCategoryID 
       4: INNER JOIN Sale S ON P.ProductID = S.ProductID 
       5: Group By PC.ProductCategoryID, PC.ProductCategoryName
       
  10. Click the "Next>" button
  11. You can test the query to verify expected results 
  12. Finally click the "Finish button"

TestQueryscreen

Chart Control

  1. Expand the "Data" section in the toolbox
  2. Drag/drop a "Chart" control onto the design service in the body of the web form
  3. Select the Chart control just added to the design surface and select the carrot.
  4. In the "Choose Data Source" select the Sql Data Source object that was defined in earlier steps
  5. Set the "Chart Type" drop down to "Pie"
  6. Set the "X Value Member" to ProductCategoryName
  7. Set the "Y Value Member" to TotalSales

At this point running the application provides a nice pie chart with the corresponding category labels.

Chart

Chart Tooltips
*Adding tooltips is an easy task and one that is commonly requested, and expected by end users.

  1. Select the Chart control on the design surface
  2. Open the properties window
  3. Locate the "Series" property and click the ellipsis to open the "Series Collection Editor"
  4. In the left pane make sure "Series1" is highlighted
  5. On the right pane scroll down until you locate "ToolTip"
  6. Click the ellipsis to open the "String Keywords Editor" dialog
  7. In the String Keywords Editor dialog click the button "Insert New Keyword"
  8. Select the option "Y Value as Percentage of Total"
    1. You can customize the formatting of the tooltips by changing values in the "Format" drop down.
    2. To create your own custom formatting select the "Custom" option in the "Format" drop down list.
  9. Click the "Ok" button on Keyword Editor dialog
  10. Click the "Ok" button on the String Keywords Editor dialog.
  11. Click the "Ok" button on the Series Collection Editor dialog.
  12. Run the application you should see tooltips specific to each section of the pie graph. 

ChartWithTooltip

Hopefully at this point you will feel comfortable exploring the various chart types their associated properties.  Microsoft chart control is a fairly simple control with numerous features.  In future blogs I will provide additional charting examples.

~Happy Charting~

Visual Studio 2010 C# Project Source

SQL Database and Sample Data


Posted by: Jim Rouse
Posted on: 5/23/2011 at 1:53 PM
Tags: ,
Categories: .NET | ASP.NET | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (3) | Subscribe to this BlogRSS comment feed

Increase SERP With Good Page Load Using CSS Sprites

The Why

Around this time last year, Google officially announced that page load time is a new factor that can have an effect on our SERP. This means that Google's page rank algorithm may reward certain websites with a better SERP simply because they load faster. Even though Google claims that this new factor accounts for less than 1% of search queries, any website that values a high organic page ranking should take the change seriously.

Having a faster website not only has the potential to boost (or maintain) SERP, it also has a positive effect on the user's experience. Akamai Technologies, innovators of one of the world's leading CDN, sponsored a research study on the retail website performance and concluded that "the consequences for an online retailer whose site underperforms include diminished goodwill, negative brand perception, and, most important, significant loss in overall sales."

Methods like compression, minifying CSS and JavaScript, and caching are all common suggestions for improving a website's page load time. However, there remains a less suggested method that involves reducing the number of HTTP requests to the server by combining all of the commonly used images into one image file.

With the tools provided by webpagetest.org, we can examine the performance of any website during page load. I've created a sample webpage that is comprised of a simple HTML layout, one external CSS document, and 15 different images (27 including mouse-over images) that make up the user interface. The page load test results (the median of 10 tests) state that it takes 1.644 seconds for the page to load, which is a very respectable load time.  However, if we take a look at the nifty graph that webpagetest.org provides us with, we will notice the inefficient way in which we load our images.

Waterfall Graph for Non-Sprite Page

For every image used on the page, a separate HTTP request is made. The time spent waiting for the first byte (known as TTFB or Time to First Byte, shown as green in the waterfall graph) for each separate HTTP request is minuscule (about 100 milliseconds) and the majority of the time is spent actually downloading the image (represented by the blue). That being said, a meager 100 milliseconds multiplied by a large quantity of images can add up quickly.

Request Bar Graph for Non-Sprite Page
The majority of HTTP requests being made are for images.
Byte Bar Graph for Non-Sprite Page
The majority of bytes being downloaded are from the images used on the site.

To combat this inefficiency, we can simply reduce the number of requests being made to the server by combining all of the images used to create the site's user interface into one large image. The amount of data being downloaded will be equivalent, but there will only be one HTTP request made to get that data. Therefore, with this change, less time will be wasted during the loading of the page.

*Note that the time saved using a CSS sprite is not necessarily equal to the number of requests made for images multiplied by 100 milliseconds, as most modern browsers can make two to four requests simultaneously.

The How

I used Microsoft Paint to create and combine all of the images used in the sample web page to keep things simple:

Click here to view the version of the Sample Site that does not use a CSS sprite.

Click here to view the version of the Sample Site that does use a CSS sprite.

Both versions of the sample site have almost identical markup.  The main differences lie in the cascading style sheet.  If we take a look at the CSS rules created for the anchor element used as a register button, we can see how the image is placed without the use of a sprite:

CSS not using sprite image:

a.headerNav
{
    float: left;
    width: 162px;
    height: 43px;
    margin: 10px 0px 10px 16px;
}
a.register {background-image:url('images/register.gif');}
a.register:hover {background-image:url('images/register_over.gif');}

Markup of the register link:

<a href="#" class="headerNav register"></a>

We simply set the size of our element and its background to our register image (images/register.gif).  The mouse-over effect is created by using the "hover" pseudo-class to change the background to a different image (images/register_over.gif).   That's about it--we have our image button.

Now to get the same results using a sprite image.  Here's that same register element's style and markup:

CSS using a sprite image:

.sprite {background-image:url('Sprite.gif');}
a.headerNav
{
    float: left;
    width: 162px;
    height: 43px;
    margin: 10px 0px 10px 16px;
}
a.register {background-position:-165px -260px;}
a.register:hover {background-position:-165px -310px;}

Markup of the register link:

<a href="#" class="headerNav register sprite"></a>

Notice that we're now using another class I chose to call sprite.  The only property set in this class is the background-image property and it's pointing at the sprite I created with Paint:

sprite

I chose to place this property in a new class called sprite because I knew many other elements on my page would use the same image as their background.  Instead of setting the property for each element separately, I chose to place each element using my sprite image into the sprite class.

The rest of the styles are almost exactly the same.  The only difference is that we no longer set the background-image property for our register class.  Instead, we specify where to take a virtual slice of our giant sprite image by setting the background-position property.  This property accepts two values delimited by a space.  The first value represents horizontal positioning and the second represents vertical (x-axis and y-axis).  The size of your element, determined by the height and width properties, determines the size of the slice you take out of the sprite image.  Imagine that the background-position property designates where that rectangle (determined by your height and width properties) is positioned on your sprite.

For instance, if we set the height as 43 pixels and the width as 162 pixels, we have a virtual rectangle that looks like this (without the borders):

rectangle

The background-position property positions the top-left corner of this rectangle in our sprite, selecting a particular piece of our sprite to display.  Here's an illustration of the background-position when set to 0px 0px:

sprite1

Notice that the top-left corner of our virtual rectangle is located at the top-left of our sprite, as our background-position coordinates were specified to be 0px from the left and 0px from the top.  Currently, this displays a portion of our header logo, which is not what we were going for.  If we change the background-position property to be -165px -260px, the rectangle would select the register button portion of the sprite image:

sprite2

Notice that the virtual rectangle is now displaying our register button. That button is exactly what will display as the background of our element.  If we replicate this technique for every image used on the site, we'll only have made a request for this one sprite image instead of separately requesting each individual image. 

The Real Results

Let's take a look at the (much smaller) page load waterfall graph for the sample webpage that uses an image sprite:

Waterfall Graph for Sprite Page

Observe that the overall time spent on the TTFB (green) is way lower, as we only have to make three requests instead of 17.

Request Bar Graph for Sprite Page

The number of HTTP requests for images has been severely reduced.
Byte Bar Graph for Sprite Page

The amount of data downloaded has stayed the same.

With the same layout and design, by utilizing the CSS background-position property to virtually slice a single image sprite instead of separately requesting individual images, we've managed to go from 1.644 seconds down to 1.172 seconds taken to load the sample page.  That's a 472 millisecond (29%) improvement!  Not too bad considering all we had to do is toss all of our images into one image file and change the way we work with images in CSS.

Feel free to download the source of the sample pages for your own use:

Sample Page Source

Here are the links again to both pages:

Sample Page that does not use a CSS sprite.

Sample Page that does use a CSS sprite.

If you're interested in web development, I suggest browsing Intertech's website for available training courses.


Posted by: Tom Faltesek
Posted on: 5/6/2011 at 7:25 PM
Tags: ,
Categories: Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

Windows Azure Multiple Web Sites

by Jim White (Director of Training and Instructor)

With Windows Azure SDK 1.3, you can run multiple Web Sites in a single Web role.  Prior to Windows Azure SDK 1.3, each Web role ran a single Web application.  This constraint was largely because Web roles were hosted in IIS Hosted Web Core where a single application was bound to a single HTTP/HTTPS endpoint.  Now, Windows Azure supports full IIS capabilities allowing Web roles to support multiple Web sites and Web applications.

Create or Add Existing Web sites to a Cloud Project

Multiple Web sites and applications are accomplished using Web sites, virtual applications, and virtual directories features in IIS 7.0.  You can find more information about these IIS 7 features here.  Once you have a Windows Azure project with an existing Web role, you can create or add existing Web sites to the project.  With the new Windows Azure Tools for Visual Studio version 1.3 (or better), there is nothing Azure-specific that needs to be done to create or add a Web site to the solution.  Simply use the existing VS means of creating or adding a Web Site to the solution containing your Windows Azure project.
imageIn this example, a virtual application and virtual directory Web sites were added to a HelloWorld project.imageHowever, without any other work, if you were to run this application in the cloud or on the Compute Emulator, only the HelloWorld Web role would be accessible.  Neither of the two new Web sites could be reached.

Making Web Sites Accessible

In order to incorporate the Web sites into the Windows Azure project, new elements need to be added to the service definition file (.csdef).  Specifically, you need to add a new <VirtualApplication> and <VirtualDirectory> elements for the Web sites added to the solution.  Unfortunately, there are no tools to accomplish this task at this time.  You must open the service definition file and add the XML necessary to define your Web sites.  When you open the service definition file, you find there is an existing <Site> child element to the <Sites>.

<WebRole name="HelloWorldWebRole">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
...
</WebRole>

This site is for the existing Web role endpoint ? the HelloWorldWebRole in this example.  Add child <VirtualApplication> and <VirtualDirectory> elements to the <Site> in order to add virtual application and virtual directory Web sites.  The example virtual application and virtual directory from above are added here.

<WebRole name="HelloWorldWebRole">
<Sites>
<Site name="Web">
<VirtualApplication name="HelloWorldVirtApp"
physicalDirectory="../../WebSites/HelloWorldVirtualApplication" />
<VirtualDirectory name="HelloWorldVirtDir"
physicalDirectory="../../WebSites/HelloWorldVirtualDirectory" />
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites>
...
</WebRole>

Now the Web sites (virtual application and virtual directory) can be accessed through Azure or the Compute Emulator.  Simply use the virtual application name with the Web role URL to access the virtual application Web site.image image Use the virtual directory name and resource name with the Web role URL to access a resource in the virtual directory.image

Using the Old Hosted Web Core

You can still run in the old-style Hosted Web Core mode.  This limits the capabilities of your application ? such as having multiple Web sites per role.  To run in Hosted Web Core versus full IIS 7, simply remove the <Sites> element from the service definition file.

<WebRole name="HelloWorldWebRole">
<!-- <Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="Endpoint1" />
</Bindings>
</Site>
</Sites> -->
...
</WebRole>

A better understanding of the differences (and impact) of running Full IIS 7 versus running in Hosted Web Core can be found in a blog post by the Windows Azure Team here.

More Information

I found the following MSDN articles and blog posts to be helpful in learning about Multiple Web Sites with Azure.

http://www.wadewegner.com/2011/02/running-multiple-websites-in-a-windows-azure-web-role/
http://msdn.microsoft.com/en-us/library/gg433110.aspx
http://blog.bareweb.eu/2011/01/azure-running-multiple-web-sites-in-a-single-webrole/
http://blogs.msdn.com/b/avkashchauhan/archive/2011/01/24/dissection-of-a-windows-azure-sdk-1-3-based-asp-net-web-role-in-full-iis-mode-amp-hwc.aspx

Wrap Up

I recently completed writing the update (version 3) of Intertech's Complete Windows Azure class.  Here's a list of what's new in the class.

-    All text and labs have been updated to cover the new Windows Azure Developer Portal 
-    All labs have been updated to use Windows Azure SDK ver. 1.3 
-    A chapter on Windows Azure Administration was added to include material on subscriptions, how to set up and utilize co-administrators, understanding Windows Azure OS Family and Guest OS, Remote Desktop to Windows Azure virtual machines, and more. 
-    A new lab was added to try Remote Desktop into an Azure virtual machine. 
-    Lab material was added to explore co-administration of Windows Azure. 
-    A new lab was added to explore SQL Azure and tools for creating and exploring databases in the cloud. 
-    Lab material was added to explore how to see how to publish to Azure directly through Visual Studio (bypassing  the Developer Portal). 
-    Material was added to explore Web roles with multiple Web sites. 
-    All labs and text have been updated to include Visual Basic code samples and lab solutions (in addition to C# samples and lab solutions). 
-    An explanation of the new extra small VM and use of the extra small VM in labs. 
-    A quick look at the VM Role and how it relates to the other parts of Windows Azure Compute. 
-    A look at using IntelliTrace in Visual Studio to debug and examine applications running in the cloud.

Click here for more details on Intertech's Complete Windows Azure class.  If your team needs help implementing an Azure solution, contact Ryan McCabe (Intertech's account representative for Azure) at rmccabe@intertech.com.  As always, I also encourage you to register with the Virtual Azure User Group (azureug.net).  We meet monthly in virtual space and share our knowledge and experiences on Azure.


Posted by: Jim White
Posted on: 5/2/2011 at 11:06 AM
Tags: , , , ,
Categories: .NET | Cloud Computing | Web Development | Windows Azure
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

ASP.NET MVC Training Video

Microsoft's standard .aspx Web forms are a fine model for developing Web pages. However, an alternative design pattern has been gaining popularity in the "ALT .NET" arena for ASP.NET – the ASP.NET Model-View-Controller (MVC) design pattern. Although this method has already been utilized greatly with Java, such as with JavaServer Faces, Struts, and Spring MVC, ASP.NET developers are choosing to mold the standard page architecture for its support for Test Driven Development (TDD), a clear separation of user interface (UI) and presentation logic, and more intuitive Web URLs. With no prior knowledge of Java or MVC expected, attendees should expect to first learn the “why’s and how’s” of ASP.NET MVC. They will why ASP.NET MVC should be considered and how the free ASP.NET MVC framework encapsulates the essential components of MVC. This framework is capturing an amazing amount of attention from the ASP.NET developer community.


Posted by: Intertech
Posted on: 10/19/2010 at 1:56 PM
Categories: .NET | Visual Studio | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed

Microsoft Security Advisory 2416728 - ASP.NET Vulnerability

There is a report of ASP.NET vulnerability.

According to Microsoft, "The vulnerability exposes viewing data, such as the View State, which was encrypted by the target server, or read data from files on the target server, such as web.config. This would allow the attacker to tamper with the contents of the data. By sending back the altered contents to an affected server, the attacker could observe the error codes returned by the server. Microsoft is aware of limited, active attacks at this time."

Here's a link to more information on Microsoft's website.


Posted by: Intertech
Posted on: 9/22/2010 at 12:53 PM
Categories: .NET | Visual Studio | Web Development
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Subscribe to this BlogRSS comment feed
Contact Us 651-994-8558 1-800-866-9884
Home | Training | Curriculum | Course Finder | Schedule | Enroll | Twin Cities Java User Group | Consulting | Foundation | Jobs | About Us | Our Story | Press Room | Instructors | President | Map & Directions | Sitemap

Java Training | JSF / Struts / Spring / Hibernate Training | Java Power Tools Training | .NET 4.0 & Visual Studio 2010 Training | .NET 3.5 and Visual Studio 2008 Training | .NET 2.0 and Visual Studio 2003 Training | Prism / MVVM / MEF Training | Microsoft Web Development Training | Cloud Computing Training | Ajax / Web Services / XML Training | Groovy and Grails Training | SQL Server 2008 Training | SQL Server 2005 Training | Mobile Development Training | SharePoint 2010 Training | SharePoint 2007 Training | Agile, Process, Analysis & Design Training | Arch/Design Patterns Training | Microsoft Official Curriculum Training | Web Development Training | Ruby Training | Rational Application Developer (RAD) Training | WebSphere Application Server Training | WebSphere Portal Training | WebLogic Training | Boot Camp Training | Project Management Training | C++ Training | Metro / WinRT / Windows 8 Development Training | Retired

Intertech delivers training on-site and virtually serving cities including Phoenix, AZ | San Francisco, CA | Los Angeles, CA | San Diego, CA | San Jose, CA | Washington, DC | Chicago, IL | Orlando, FL | Boston, MA | Duluth, MN | Minneapolis St. Paul, MN | Rochester, MN | Raleigh-Durham, NC | New York, NY | Philadelphia, PA | Austin, TX | Dallas, TX | Houston, TX | Seattle, WA.