Blog Archives

WPF: Using ListBox and StackPanel to Display Multiple Properties

Introduction

This blog builds on the previous one.  That earlier blog uses an ObjectDataProvider to access a collection of DrinkProduct objects and displays the ProductName property.

finished

It’ll be a rare day when you only need to access a single property of a collection like this.   Very often you’ll want to display some kind of key list, like the ProductName, first and then show users further details as they select individual items from the ListBox.  So that’s what we’ll look into here.

I’m going to use a very basic approach, putting everything inside a parent StackPanel.  So we can see what we’re aiming for, here’s the finished window:

DrinkProductStocks

You can see that the Instant Tea item is selected and that the correct Product ID and current stock figures for this item are shown.  As the user changes the selection, so the details on the right hand side will change to reflect the current choice.

The Document Outline Window

Because the XAML might take a bit of studying to see what goes where, one tool that you’ll often find useful is the Document Outline in the IDE.  You can select this with  Ctrl + Alt + T, or find it in the View menu.  It is very useful for getting an overview of the structure of the Window:

DocumentOutline

In this example, we’re interested in the first StackPanel and everything below that in the displayed list of controls (actually, to be totally accurate, they’re ‘elements’ in WPF, but old habits die hard!). 

The first StackPanel, which is named PanelOuter contains two children – a ListBox named lstDrinks, and another StackPanel, which  is named PanelRight.  PanelRight also has children – in this case two labels and two text blocks.  So, essentially, the outer StackPanel is split vertically, has a ListBox in the left half and a StackPanel with its own content in the right half.  The Document Outline is often most useful for working out the nesting pattern of elements when things get complicated.

Markup for the Window

Here’s all the markup for the window.  I’ll pick through it in the next few sections and highlight the parts you really need to home in on.

 

    1 <Window x:Class="MainWindow"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4        xmlns:local="clr-namespace:ObjectDataProviderBlogDemo"

    5    Title="Drink Product Stocks" Height="350" Width="375">

    6 

    7     <Window.Resources>

    8         <ObjectDataProvider x:Key="DrinksInfo"

    9         ObjectType="{x:Type local:DrinkProduct}"

   10         MethodName="StockCheck"></ObjectDataProvider>

   11     </Window.Resources>

   12 

   13         <StackPanel Orientation="Horizontal" Name="PanelOuter"

   14                DataContext="{Binding Source={StaticResource DrinksInfo}}">

   15 

   16             <ListBox Name="lstDrinks" Margin="2,4,14,2" Padding="1,0,16,1"

   17            ItemsSource="{Binding}"   IsSynchronizedWithCurrentItem="True"/>

   18 

   19             <StackPanel Orientation="Vertical" Margin="15,3,3,3"

   20                        Name="PanelRight">

   21             <Label Content="Product ID" Foreground="MediumBlue" />

   22             <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

   23                        Text="{Binding Path=ProductID}"></TextBlock>

   24             <Label Content="Quantity Available" Foreground="MediumBlue"

   25                   Margin="3,45,3,3" />

   26             <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

   27                         Text="{Binding Path=Quantity}"></TextBlock>

   28             </StackPanel>

   29         </StackPanel>

   30 

   31 </Window>

   32 

Markup for the Window Opening Tag and Window Resources

This is exactly the same as I used in the previous blog item, so I won’t go over it again here.

Data Binding Markup for the Outer StackPanel

Bearing in mind that several of the elements inside the outer StackPanel need to be bound to the data source, it makes sense to set the data binding on this outer item. Here’s the opening tag for that StackPanel:

         <StackPanel Orientation="Horizontal" Name="PanelOuter"

                 DataContext="{Binding Source={StaticResource DrinksInfo}}">

This time I’ve created a DataContext that ensures that the DrinkProduct data from the ObjectDataProvider is available throughout the StackPanel. 

Data Binding Markup for the ListBox

Because the ListBox is a child of the StackPanel, there’s no longer any need to reference that DrinksInfo StaticResource directly.  But the ItemsSource still needs to know where its data is coming from, so a simple Binding which links to the default parent binding is used:

      <ListBox Name="lstDrinks" Margin="2,4,14,2" Padding="1,0,16,1"

          ItemsSource="{Binding}"   IsSynchronizedWithCurrentItem="True"/>

The other addition to the ListBox markup is the IsSynchronizedWithCurrentItem property. This is an important feature in these kinds of scenarios where the user clicks on a ListBox item and this is meant to update some other bound control(s).  It’s a very long-winded property name, but simply all it means is that all other elements that are bound to the same source listen for this, and are automatically updated when any changes happen.

Markup for the Right Hand Panel

There are several ways of creating the same finished layout.  This one is reasonably straightforward.  The labels have static content that describe what’s in the TextBlocks below them.  If you wanted to have the label and the TextBlock aligned horizontally, you could insert further sub StackPanels inside PanelRight.

I don’t know of a way to concatenate the static text and the bound result in a single control by using the XAML markup in the window (in other words to have something like “Quantity: 123” inside a single TextBlock).  But if you’re determined to get this result, you could use a ValueConverter.

The TextBlocks are both bound to the same data source – again channelled through the DataContext of the parent PanelOuter StackPanel.  Each of them has a path to a different field.  In the case of the first TextBlock, that path points to the ProductID field:

     <TextBlock Margin="3" Padding="3" HorizontalAlignment="Center"

             Text="{Binding Path=ProductID}"></TextBlock>

Summary

And that’s pretty much all there is to it.  I’ve attached the sample project if you want to experiment.

An introduction to dates and times in Visual Basic.NET (2)

What’s today’s date?
In the previous blog on this topic, I looked at the basics of the DateTime object. You saw some of the output formats and learnt about the Now and Today properties. I’m going to dig a bit deeper into those subjects this time.

Here’s a code snippet that creates a DateTime that has today’s date as its date value. It then pulls out just the value of the Day part

     Dim dt As New DateTime

    dt = Today

    Console.WriteLine(dt.Day)

As I’m writing this on the 25th August 2010, the value I see is 25.

you can apply the same kind of evaluation to get the month or the year:

    Dim dt As New DateTime

    dt = Today

    Console.WriteLine("Current month is " & dt.Month)

    Console.WriteLine("Current year is " & dt.Year)

 

 

The output for me today will be:

Current month is 8
Current year is 2010

What time is it, Mr Wolf?
Although you saw in the previous blog that you can isolate and display the time element of a DateTime, there might be an occasion when you want to extract just the value of the hour or minute, for example.  The way to do this is similar to that for the date:

    Dim dt As New DateTime

    dt = Now

    Console.WriteLine("Current hour is " & dt.Hour.ToString)

The result for me sat here at 11.33 in the morning is:

Current hour is 11

I could do the same thing for the minute or second if I needed that information.

If you read my previous blog on this topic, you’ll remember that I pointed out the subtle difference between Now and Today.  You’ll see that in this last snippet I used Now, and not Today.  If I hadn’t done this, the result would be zero.

What day is it?
Another useful property of the DateTime object is DayOfWeek.  Check out this snippet:

    Dim dt As New DateTime

    dt = Now

    Console.WriteLine("Today's day of the week is " & dt.DayOfWeek.ToString)

The result will be something like:

Today's day of the week is Wednesday

If you’re comparing dates, you might sometimes want to know if one date is earlier or later in the current year than another. Although there are other tools for date and time manipulation, you can do some of the basics by using the DayOfYear property. This next snippet shows how:

    Dim dt As New DateTime

    dt = Now

 

    Dim dt2 As New DateTime(2010, 12, 12)

    Console.WriteLine(dt2.DayOfYear – dt.DayOfYear)

It creates two DateTime instances, then subtracts the values of their DayOfYear properties to find how many days separate them.  In reality, you’ll probably use a TimeSpan object (which I’ll be coming on to soon), but this is an option anyway.

Comparatively Speaking
Using the comparison method above is a bit limited, so you may want to use the CompareTo method of DateTime instead, particularly if the two dates spread across more than one year. In a real world scenario, you wouldn’t generate known dates in the way I’ve done in the sample below.  You’d be taking them from users or grabbing them from data sources somewhere. But for the purposes of this demonstration, I’ll create the DateTime values in the snippet.

    Dim dt As New DateTime(2000, 12, 1)

    Console.WriteLine(dt.CompareTo(DateTime.Now))

A couple of points to note here.  You’ll see in the second line that I’ve used Now as one of the values, but I didn’t create a separate instance to hold the value. This can be a useful shortcut in these kind of situations. The second point is that the values that will be returned are either –1 if the dt date is earlier than the current date, 1, if the dt date is later than the current date or 0 if they are the same.

Don’t let my sample confuse you into thinking that you have to use Now.  You can use any date you like for the second date value.

Depending on what you’re doing with them, the returned values of –1, 0 or 1 may need to be translated into something a user can relate to.  The following approach will do this.

    Dim dt As New DateTime(2020, 1, 1)

 

    Dim infostring As String = String.Empty

    Select Case (dt.CompareTo(DateTime.Now))

      Case -1

        infostring = "earlier than"

      Case 1

        infostring = "later than"

      Case 0

        infostring = "the same as"

    End Select

    Console.WriteLine("The first date is {0} the second date", infostring)

The result will be something like :

The first date is later than the second date

Performance tuning tricks for ASP.NET and IIS 7 – part 2

In part 1 of this series, we looked at some tricks to optimize the performance of any website running in IIS 7 by only modifying the web.config. In this part we will focus on handling browser caching issues and optimize the number of JavaScript and CSS files loaded from an ASP.NET website.

NB! All the code (a single .cs file of 125 lines) is included in the zip file at the bottom of this post.

Browser caching

In part 1, we looked at how it was possible to set an expiration header to any static file such as JavaScript and CSS files, so the browser would cache them for a long time and thereby optimize both for bandwidth and the number of requested files going from server to browser.

The problem with setting a browser cache expiration date of i.e. a JavaScript file to a year in the future becomes clear when you change the file before it expires in your visitor’s browsers. They simply won’t see the changes until they either clear their cache or hits F5 manually.

Adding the version number

The only viable way to maintain a far-in-the-future expiration date is to change the URL of the file when the file changes. So instead of including script files like so:

<script type="text/javascript" src=”/scripts/global.js"></script>

…we really want to get a version number included in the src attribute, like so:

<script type="text/javascript" src=/scripts/v_634174870689341736/global.js"></script>

The problem with this is that ASP.NET doesn’t have any feature that will inject a version number, so we have to create that our selves. It is very simple to do so by looking at when the file was last changed and then retrieve the ticks from that date. In the zip file below you’ll find a method that does exactly that and it can be used like so:

<script type="text/javascript" src="<%=BundleHelper.InsertFile("/scripts/global.js") %>"></script>

The BundleHelper.InsertFile method is one you want to use for Stylesheets as well, like so:

<link rel="Stylesheet" href="<%=BundleHelper.InsertFile("includes/style.css") %>" type="text/css" />

Ok, now all our JavaScript and stylesheet references have the version number in the path. Next thing to look at is getting it working with the updated non-existing path.

The HTTP handler

To be able to serve the correct file even with the version number in the path, we need to register an HTTP handler in the web.config’s <system.webServer> section like so:

<add name="ScriptBundler" verb="GET,HEAD" path="*.js" type="FileBundleHandler" />
<add name="CssBundler" verb="GET,HEAD" path="*.css" type="FileBundleHandler" />

The handler we just registered is called FileBundleHandler and knows how to filter out the version number to find the right file. It supports both .css and .js files. The handler also makes sure to both output cache and browser cache correctly. Just add the FileBundleHandler.cs file from the zip file to your website and you are up and running.

Now the browser cache issue has been resolved by adding a version number to the path of the included file and by adding an HTTP handler that knows how to remove it again when serving the file.

Bundle multiple files

Another common website performance issue is that there are many JavaScript and CSS files included on a page. This scenario results in the browser have to download a lot of extra files and that all slows down the performance of a website. The solution to this is also very simple when you’ve first completed the above steps to register the HTTP handler in web.config and called the BundleHelper.InsertFile method when inserting JavaScript and CSS files.

The folder structure convention

There are many ways of bundling files into a single request, like Justin Etheredge’s Squisher. For this example I have chosen a convention based approach because that doesn’t require any code to implement.

Any given ASP.NET website might have a folder structure similar to this:

The folder convention supported in the FileBundleHandler lets you reference a folder instead of just a file. Both the HTTP handler and the BundleHelper.InsertFile understand when a folder is referenced and automatically bundles all the .js or .css files to a single response. So in order to bundle all the files in a given folder, simply reference the folder name and add the extension of the types of files you want bundled. Having the folder structure above, you can add a bundle like so:

<script type="text/javascript" src="<%=BundleHelper.InsertFile("/scripts/common.js") %>"></script>

Notice that the file /scripts/common.js doesn’t exist, but the folder /scripts/common does. By adding .js at the end, we tell the HTTP handler to look for all files with the same file extension – in this case .js files. It bundles all the files in alphabetical order and serve the as a single response. For security reasons, the HTTP handler will only serve .css and .js extensions.

Minification

Since we are now running all JavaScript and stylesheet files in bundles and through the HTTP handler, it makes sense to also look at the content of the files to optimize even further.

For this example I’m using the Microsoft Ajax Minifier (MAM), which is a single .dll file capable of minifying both JavaScript and stylesheets. The MAM is my favorite JavaScript minifier since it not only removes whitespace, it also rewrites variable and function names and a lot of other things as well. For me it has proven a better choice than the YUI Compressor and Google Closure Compiler. The stylesheet minifier feature of MAM also looks very nice, but I have honestly never used it before except for this example.

Basically what MAM does is that it optimizes and removes unwanted whitespace from both JavaScript and stylesheets. The HTTP handler makes use of MAM for both single files and bundled ones, so you get full benefit no matter your scenario.

Summary

No matter if you use the website model, the web application model or ASP.NET MVC you are now able to utilize the browser cache to the fullest. Furthermore, by bundling your files using the folder convention you can minimize the number of requests sent by the browser. Both JavaScript and stylesheet files are also minified and optimized for even smaller file sizes sent over the wire.

It’s worth noticing that the output caching respects file changes and therefore refreshes evertime changes are made to the JavaScript and CSS files tunnelled through this code.

Following the techniques in part 1 combined with this example will improve any website’s server-to-browser performance substantially.

Implementation

  1. Download the zip file below and place the AjaxMin.dll in your bin folder.
  2. Then place the FileBundleHandler.cs in your App_Code folder if you use the website model – otherwise place it where ever it makes sense in your structure.
  3. Now register the HTTP handler in your web.config under the <system.webServer> section like so:

    <add name="ScriptBundler" verb="GET,HEAD" path="*.js" type="FileBundleHandler" />
    <add name="CssBundler" verb="GET,HEAD" path="*.css" type="FileBundleHandler" />

  4. The last thing you need is to start using the BundleHelper.InsertFile method on your pages for both JavaScript and stylesheets like so:

    <script type="text/javascript" src="<%=BundleHelper.InsertFile("/scripts/common.js") %>"></script>
    <link rel="Stylesheet" href="<%=BundleHelper.InsertFile("styles/global.css") %>" type="text/css" />

Download

FileBundler.zip (89,95 kb)

Quick Tip: Eject a CD/DVD via the Menu Bar

Apple has a long history of using slot-loading disc drives rather than the tray-loading drives used widely across the rest of the industry. If you want to eject the disc, there are currently two ways of doing this in OS X that most users know of, but there’s actually a hidden app that you may not know about.

You can eject from the sidebar in Finder, or from the desktop (dragging to the trash). However, there’s also a third way: a menu bar item. Apple doesn’t show this item by default in Snow Leopard, which led me to try and find a way to enable it. It’s actually fairly easy:

  1. Open a Finder window and go to /System/Library/CoreServices/Menu Extras.
  2. Double click on Eject.menu and it should appear instantly in your menu bar.

You can move the menu bar item by holding down the Command key and dragging it around. You can also get rid of it by dragging it off the menu bar, where it’ll vanish in a puff of smoke, just like you’d drag an item off the Dock.

Updated Flash Player Enables Hardware-Accelerated Video on OS X [Updates]

Windows users have been enjoying hardware-accelerated video decoding since the Flash 10.1 Final release; now the latest Flash Player release for Macs (10.1.82.76) officially brings GPU decoding to OS X—in theory resulting in better video playback on your Mac. [Adobe via ByteArray.org] More »







ServerInfo – Easily scan a Machine/Server Farm for Information

new open-source project in Asp.Net MVC 2

More than once I have been asked what databases are on what server, if server X is running application Y or what websites server ABC is running. These are are relatively simple things to accomplish, and there are tools available to get this information, but this is an extremely simple and portable solution – all the data is kept in xml, so there is no need to install a backend.

All that it is required to get all this information is to enter ip addresses and the user has the rights to scan the machines requested.

In addition, this can keep track of all of the owners of the machines and has a GUI for running WMI Queries, which is extremely powerful if you know how to use it.

This is written with Asp.Net MVC 2, C# and xml; it requires .Net 4.0 framework. I will be updating this to MVC 3/Razor in the near future.


using Server.MapPath() in an Generic Handler (.ashx)

if you need to get a local file path in your ashx

Instead of using:

Server.MapPath()

Simply use:

System.Web.HttpContext.Current.Server.MapPath()


Inline AJAX DropDown and Text Editing with Asp.Net MVC and jQuery

including how to use a database to populate the dropdown


First thing is first, you will need to download
jQuery
and the
Jeditable
plugin (I prefer to refer to it as the Jedi-Table!).
Be sure to put these references in your View (or Masterpage).
Next, you have to set up a view on which to use an inline edit.
I find that I often want to use this approach on tables of information.
For this View, I will set it to use an IEnumerable of an Item I have called ‘ItemOwner’ (this is arbitrary and does not really matter).
It will be a simple table that lists the Name and the Country of the owner, both of which will be editable inline.
Here is the Index in my ExampleController.cs:

myDataContext db = new myDataContext();
public ActionResult Index()
{
    // get the info for the 'Countries' dropdown:
    ViewData["countries"] = db.Countries
        .Select(x => new SelectListItem()
        {
            Text = x.Name,
            Value = x.Id.ToString()
        }).ToJson();

    // get the 'ItemOwners' I am interested in:
    var owners = db.ItemOwners.Take(3);

    return View(owners);
}

As you can see there, I am also pulling the countries from the database and throwing them into the ViewState – we will get to this later.
Since the Country is actually a foreign key relation, the value is set to an integer which is the identity field in the database.
It is also using a .ToJson() extension which takes a IEnumerable<SelectListItem> and
puts it into a simple JSON string that I use which is here:

public static string
    ToJson(this IEnumerable<SelectListItem> slis)
{
    string output = "{";
    if (slis != null)
    {
        for (int i = 0; i < slis.Count(); i++)
        {
            output += " '" + slis.Skip(i)
            .First().Value + "': '" +
            slis.Skip(i).First().Text + "'" +
            (i == slis.Count() - 1 ? " " : ",");
        }
    }
    return output += "}";
}

There is probably a better way to do that… but I don’t know it?!

I am also pulling 3 ItemOwners from the database, I know this is silly, but it just an example.
Here is how I am displaying them in the view:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
        </tr>
    </thead>
    <tbody>
        <% foreach(var owner in Model) { %>
        <tr>
            <td><%= owner.Name %></td>
            <td><%= owner.Country.Abbreviation %></td>
        </tr>
        <% } %>
    </tbody>
</table>

Now that there is a simple table we want to make it a bit more interactive.
Since we aregoing to make all of these fields editable, we need to add in a way to distinguish exactly what they are.
To do that, we will need two things: the id of the item they are editing, and the type of inline editing we will be doing (i.e. dropdown or text input).
So to do that, let’s add in a few css classes and an identifieng ID:

<td id="name<%= owner.Id %>" class="editable text">
    <%= owner.Name %></td>
<td id="ctry<%= owner.Id %>" class="editable dropdown">
    <%= owner.Country.Abbreviation %></td>


And now add a little css to make them appear to be clickable:

td.editable:hover
{ cursor:pointer; background-color:Orange; }

Now they all look like you can click on them, so we can move on to making the click actually do something.



This is where the jQuery comes in, and it is very simple.
I have made these ‘helper’ methods in Javascript to make all of my inline calls centrally controllable, I keep this in my sites script folder so if I change one inline edit, I change them all; it also makes for more readable Javascript on each page.

function InlineDropdown(collectionToDropDown, ajaxAddress, dropDownDataSet) {
    collectionToDropDown.editable(ajaxAddress,
    {
        data: dropDownDataSet,
        type: 'select',
        indicator: 'saving...',
        tooltip: 'click to edit...',
        submit: 'Save',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextbox(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        indicator: 'saving...',
        tooltip: 'click to edit...',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextarea(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        type        : 'textarea',
        rows        : 4,
        indicator   : 'saving...',
        tooltip     : 'click to edit...',
        style       : 'inherit',
        submit      : 'Save',
        onblur      : 'ignore',
        placeholder : 'click to edit'
    });
}

Obviously you can read all about the options on the Jeditable
page, but this is how I set them.
Also notice I have a InineTextarea included as well for a textarea which is not covered here but works the exact same.

Now the jQuery calls are almost trivial:

InlineTextbox(
    $('td.editable.text'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>"
);

InlineDropdown(
    $('td.editable.dropdown'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>",
    <%= ViewData["countries"].ToString() %>
);

What that is doing is sending the POST requests to the specified address.
The POST contains a few things:

  • id – the id of the element that sent the request
  • value – the new value passed by the element

We are also passing more information there – remember that we passed both the type of field to edit and the id of the ItemOwner to edit, ie [name837] which emans we want to edit the Name field of ItemOwner 837.
So we simply set up an ashx handler (which we specified above) to do the dirty work:

public void ProcessRequest(HttpContext context)
{
    string newValue;
    try
    {
        myDataContext db = new myDataContext();
        string elementId = context.Request.Form["id"];

        // since we made the first 4 of the id the 'field' whic to edit
        // we can just pull the first 4 letters for use in our switch:
        string fieldToEdit = elementId.Substring(0, 4);

        //now take anything after those 4 and it is the Id:
        int idToEdit = Convert.ToInt32(elementId.Remove(0, 4));

        // the value is simply a string:
        newValue = context.Request.Form["value"].Trim();

        // now that we have the id, get the ItemOwner from the db
        ItemOwner owner = db.ItemOwners.FirstOrDefault(x => x.Id == idToEdit);

        // after all is said and done, we will return newValue to the user so the field
        // looks as if the change has taken place (which it has)

        // using the field we pulled above, decide what to do:
        switch (fieldToEdit)
        {
            // name is easy
            case "name": owner.Name = newValue; break;

            // since the country is an integer foreign key, we need to Convert.ToInt32:
            case "ctry":
                owner.CountryId = Convert.ToInt32(newValue);
                // now that we have recorded the value, we want to return the text to
                // the user and not the id value which would make no sense
                newValue = db.Countries.FirstOrDefault(x => x.Id == owner.CountryId).Abbreviation;
                break;
            // if it wasn't caught, something is wrong:
            default: throw new Exception("invalid fieldToEdit passed");
        }

        db.SubmitChanges(); // save it
    }
    // now if an exceptions were reported, the user can see what happened
    // this also inform the user nothing was saved
    // you could easily make this not reported to the user and logged elsewhere
    catch (Exception ex)
    { newValue = "Error: " + ex.Message + " [nothing written to db]"; }

    //now return what you want in the element:
    context.Response.Write(newValue);
}

And that is all it takes.

How to Run Mac OS X in VirtualBox on Windows [How-to]

If you’re on Windows, need to use OS X, but don’t want to buy or build a new computer, reader Bobby Patton shows us how to run Snow Leopard in a virtual machine on Windows with just a few tweaks. More »









Mac OS XOperating systemMac OSSnow LeopardMac OS X Snow Leopard

Performance tuning tricks for ASP.NET and IIS 7 – part 1

In this first installment of performance tuning tricks for ASP.NET and IIS 7 we will look at some of the easy, yet powerful possibilities in the web.config file. By taking advantage of these few tricks we can increase the performance of any new or existing website without changing anything but the web.config file.

The following XML snippets must be placed in the <system.webServer> section of the web.config.

HTTP compression

You’ve always been able to perform HTTP compression in ASP.NET by using third-party libraries or own custom built ones. With IIS 7 you can now throw that away and utilize the build-in compression available from the web.config. Add the following line to enable HTTP compression:

<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/>

By default, only text based content types are compressed.

doDynamicCompression

Setting this attribute to true enables compression of dynamically generated content such as pages, views, handlers. There really aren’t any reasons not to enable this.

doStaticCompression

This attribute allows you to decide whether or not you want static files such as stylesheets and script files to be compressed. Images and other non-text content types will not be compressed by default. This is also something you want to enable.

dynamicCompressionBeforeCache

If you do output caching from within your ASP.NET website, you can tell IIS 7 to compress the output before putting it into cache. Only if you do some custom output caching you might run into issues with setting this to true. Try it and test it. If your website works with this enabled, then you definitely want to keep it enabled.

Tip

By default, only text based content types are compressed. That means if you send application/x-javascript as content type, you should change it to text/javascript. If you use some custom modules in your website, then you might experience conflicts with the IIS 7 compression feature.

Resources

Cache static files

To speed up the load time for the visitors, it is crucial that everything that can be cached by the browser IS cached by the browser. That includes static files such as images, stylesheets and script files. By letting the browser cache all these files means it doesn’t need to request them again for the duration of the cache period. That saves you and your visitors a lot of bandwidth and makes the page load faster. A well primed browser cache also triggers the load and DOMContentLoaded event sooner.

By adding this snippet to your web.config, all static files are cached in the browser for 1 year:

<staticContent>
     <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00"/>
</staticContent>

This setting sets the expiration date of the file one year in the future. It does that by setting an HTTP header that instruct the browser to add the file to its internal cache. If you hit F5 or ctrl-F5, the browser will request the files no matter what the expiration is set to.

A major problem with client-side caching is if your static files change before the cache expires. Then the visitor with the old version in the cache won’t see the new file until she clears the browser cache or hit F5. Therefore, this setting must be used with caution and probably with a shorter expiration time. In part 2 of this series I’ll address this problem and provide a simple solution to it.

Tip

Make sure that user sensitive information isn’t cached on the browser. It will then be available by anyone else using the same browser.

Resources

WP Like Button Plugin by Free WordPress Templates