October 2011 - Posts - Jon Galloway

October 2011 - Posts

Using Node.js in an ASP.NET MVC application with iisnode

Node.js is an event-driven I/O server-side JavaScript environment based on the open-source V8 Javascript engine. It's really easy to run it on Windows now, and if you run it under iisnode, it's actually running under a standard IIS Handler, which means you can integrate it directly into ASP.NET applications.

Node event-driven model is really interesting. There's been a lot of discussion on it lately; it's neither a cancer nor the cure for cancer, but it makes it easier to handle scaling in the small. While you can handle asynchrony in most web frameworks, it's a fundamental part of Node. There's plenty of information out there on what Node is and how it's used, so I'm going to skip over that and reference a few good introductory posts:

Some background: Herding Code podcasts, early experiments

While Node has been mentioned enough on the Herding Code podcast enough that listeners have told it's been incorporated into the (unofficial) Herding Code drinking game, we've only had two official shows dedicated to Node so far.

Our first Node show (Herding Code 102, Jan 2011) was with Tim Caswell, who runs the How To Node community blog site. I really appreciated Tim's overview, spanning from the basics of Node up through some more advanced uses. If you'd like an introduction to Node, I'd recommend listening to our interview with Tim - the portion of the show where he explained why Node is useful was clear enough that it got picked up by Read Write Web in a post titled Wait, What's Node Good for Again?

Listen: Herding Code 102: Tim Caswell on Node.js

In preparation for that interview, I followed some of Tim's tutorials and wrote my first Node code. In order to do that, I spun up an Ubuntu VM, because until recently Node didn't run very well on Windows. Since then I'd poked at it from time to time, but since it didn't really fit with my day-to-day development stack it was mostly an academic exercise.

The Windows port and libuv

That started to change this past June, when Ryan Dahl announced that Microsoft was partnering with Joyent to port Node to run natively on Windows. In Ryan's post, he mentioned that Bert Belder would be one of the developers working on that port, and earlier this month I posted our second Node show interviewing Bert. Bert talked about a lot of behind-the-scenes details about the port including:

libuv

Node previously ran on top of libev, which is Unix-only. That's now changed to use the new libuv platform library.

libuv‘s purpose is to abstract platform-dependent code in Node into one place where it can be tested for correctness and performance before bindings to V8 are added. Since Node is totally non-blocking, libuv turns out to be a rather useful library itself: a BSD-licensed, minimal, high-performance, cross-platform networking library.

It's nice to see that this is paying off already - from the number of cross-platform applications listed in Ryan's post to examples like this Leveraging Node’ libuv in Windows Azure example on MSDN.

I/O Completion Ports

Windows included support for simultaneous, asynchronous I/O with Input / Output Completion Ports (IOCP) way back in Windows NT 3.5 (circa 1994), so part of the work in getting Node running on Windows required adding IOCP support to libuv.

Cygwin

There was a previous version of Node that ran on Cygwin, for certain values of "ran." I really appreciated Bert's response when asked whether they were able to use Cygwin in this port: it was exactly the opposite of what they were hoping to accomplish. Cygwin uses a compatibility layer to allow Unix applications run on Windows, which isn't ideal for performance. In contrast, this Node effort is focused on leveraging the native platform as much as possible.

Listen: Herding Code 122: Bert Belder on porting node.js to Windows

Running Node on Windows with iisnode

Node is just a single file executable. After installing Node, here's what my install folder looks like:

2011-10-21 13h43_23

The Node executable includes a server, so to have Node listen on a port you just call createServer and tell it what port to listen on:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337);
console.log('Server running at http://127.0.0.1:1337/');

That's great for a simple case, but it's likely you'll want to have Node run under a host process, which handles things like auto-start, recovery, logging, etc. In the Unix world (from what I've read) this is often done using monit and upstart, fronted by nginx. In Windows, you can run Node under IIS using iisnode.

Tomasz Janczuk (author of iisnode) summarizes some of the benefits of hosting Node with iisnode:

  • Process management. The iisnode module takes care of lifetime management of node.exe processes making it simple to improve overall reliability. You don’t have to implement infrastructure to start, stop, and monitor the processes.
  • Scalability on multi-core servers. Since node.exe is a single threaded process, it only scales to one CPU core. The iisnode module allows creation of multiple node.exe processes per application and load balances the HTTP traffic between them, therefore enabling full utilization of a server’s CPU capacity without requiring additional infrastructure code from an application developer.
  • Auto-update. The iisnode module ensures that whenever the node.js application is updated (i.e. the script file has changed), the node.exe processes are recycled. Ongoing requests are allowed to gracefully finish execution using the old version of the application, while all new requests are dispatched to the new version of the app.
  • Access to logs over HTTP. The iisnode module provides access the output of the node.exe process (e.g. generated by console.log calls) via HTTP. This facility is key in helping you debug node.js applications deployed to remote servers.
  • Side by side with other content types. The iisnode module integrates with IIS in a way that allows a single web site to contain a variety of content types. For example, a single site can contain a node.js application, static HTML and JavaScript files, PHP applications, and ASP.NET applications. This enables choosing the best tools for the job at hand as well progressive migration of existing applications.
  • Minimal changes to node.js application code. The iisnode module enables hosting of existing HTTP node.js applications with very minimal changes. Typically all that is required is to change the listed address of the HTTP server to one provided by the iisnode module via the process.env.PORT environment variable.
  • Integrated management experience. The issnode module is fully integrated with IIS configuration system and uses the same tools and mechanism as other IIS components for configuration and maintenance.

WebMatrix templates for Node.js

While completely optional, there are also some handy WebMatrix templates which make it incredibly easy to kick the tires with Node running under iisnode. These templates are really small and simple, and don't do anything secret and magical (which is a good thing) other than give you some working code and a preconfigured web.config that maps the iisnode handler for you. Here's the contents of Empty Node project:

2011-10-21 14h40_01

As I said, this is a simple template to get you started, and I like that. There's a more involved Node.js Express template which includes some common modules like the Jade template engine, but the point I want to stress is that they're not fiddling with your registry or some secret config file or anything. They're a convenient way to quickly see some pre-configured Node.js code that Works On Your Machine(tm).

Installing iisnode and the Node.js WebMatrix templates

Scott Hanselman's done a couple of in-depth blog posts about getting started with Node on Windows using iisnode and some new WebMatrix templates:

If you'd just like to get started quickly, I recommend walking through the second post. In my case, this took just a few minutes total (as I already had WebMatrix installed). Grahame Scott-Douglas typed up some great install notes:

    1. WebMatrix Install: It took a looooong time to install, about 30 minutes. I was running quite a few things on my machine at the time, including VS2010 and SQL Mgmt Studio, but it still seemed like a heckuva long time, so be patient.
    2. node.js for Windows Install: If you save to the default downloads folder in IE9 you’ll get the “This program is not commonly downloaded and could harm your computer” message. Click on “Actions” > “More actions” and “Run anyway”. Or you can open the folder in Windows explorer and double-click the file. Once you get that far the rest is easy. It installs to “C:\Program Files\nodejs” Add it to your path so you can play with the REPL and can run .js scripts. Once it’s in your path, just type “node” at the command prompt and there you have a JavaScript REPL! Or type “node myfile.js” and run JavaScript directly on Windows. Nice!
    3. iisnode for iis7 express (x86) Install: If you don’t have Microsoft Visual C++ 2010 Redistributable Package (x86) installed then the iisnode installer will tell you that you need it. Just click my link here and get it. It installs easily and then the iisnode install is a piece of cake. (FYI: You’ll have the same “This program is not commonly … etc.” message if you try to run after downloading in IE9 and that’ll happen on the next two also.)
    4. iisnode for iis7 (x86) Install: For my messing about I didn’t really need to install it but I wanted to anyway. There were no issues.
    5. iisnode for iis7 (x64) Install: I didn’t install this, ’cause I’m using a 32 bit machine for this messing about, but if you are installing the x64 version then I’m guessing you’ll need the C++ 2010 redistributable for x64.
    6. node.js templates for WebMatrix: Easy install. Thanks to Steve Sanderson (the genius behind knockout.js) for the templates.

With that complete, you can fire up WebMatrix and you'll see two new template options:

2011-10-20 11h51_15

What's in the Node.js Express Site template

The Node.js Express Site includes some useful modules:

  • connect - a middleware system for Node
  • express - a node web framework which provides things like routing, view infrastructure, content negotiation, etc.
  • jade - a view template engine (conceptually similar to ASP.NET MVC view engines like Razor, but syntactically more similar to Haml)
  • mime - a utility module for MIME-type lookups
  • qs - standard querystring parser

Note: you can find more modules listed on the Node wiki, and there's a good discussion of how these pieces fit together on StackOverflow.

Express uses Sinatra-style routing, so the controller-ish code is in routes.js:

module.exports = function(app) {

    app.get('/', function (req, res) {
        res.render('index', { 
            message: 'Welcome to my site!' 
        });
    });
    
    app.get('/about', function (req, res) {
        res.render('about');
    });

}

Views using the Jade template engine

You'll see that a request to the root of the site (matching the pattern "/") will return the index view, passing it a JSON model containing a message that says "Welcome to my site!" Looking at the index template (/views/index.jade.txt), you'll see that Jade is extremely terse:

- locals.pageTitle = "Home page"

p= message

And that uses a layout (/views/layout.jade.txt) which is also pretty simple:

!!! html
html
    head
        if locals.pageTitle
            title= pageTitle
        link(href="/css/site.css", rel="stylesheet", type="text/css")
    body
        div.header
            h1 My Node.js Site
            nav
                a(href='/') Home
                a(href='/about') About
        != body

Hitting Run, you'll see that WebMatrix has spun up site in IIS Express and we've got a simple page.

2011-10-21 17h24_06

Side note: I'm not going to go into detail, but Jade's syntax is pretty neat. It brings in the semantic focus of Haml (available in ASP.NET as NHaml), but with some nice improvements (e.g. there's no need to prefix tags with %), and it's cool to have one language (Javascript) for both server and client side code. Example:

- locals.pageTitle = "Home page"

p= message

//Server-side logic in Javascript
- if (message.length)
  ul
    - each word in message.split(" ")
      li= word

//Client-side Javascript
script
    alert("The message is: #{message}")
 

As shown in the comments, the first bit of script runs Javascript code on the server, and the second bit of script runs Javascript code on the client. That's awesome.

2011-10-21 19h16_58

Back to that iisnode is an IIS Handler thing

Okay, so Node is of course interesting and useful on its own - the above sample shows an application with routing, a nice view engine, etc. If you want to handle the hosting yourself, knock yourself out. If you're using Windows, you've got IIS available, and iisnode can host the Node process for you.

I really like new toys that play well with existing technologies, and one cool advantage of iisnode is that you can use it to integrate Node directly into an existing ASP.NET application. That all works because iisnode is an HttpHandler, which has been supported in .NET since .NET 1.1. That means that you can seamlessly route ASP.NET requests to ASP.NET and Node requests to Node.exe (running under iisnode) using the standard mechanisms the ASP.NET and IIS have supported for a very long time.

A simple iisnode web.config example

If you look the web.config in the Node.js Express Site, you can see how the iisnode handler is configured:

<configuration>
    <system.webServer>

        <handlers>
            <!-- indicates that the app.js file is a node.js application to be handled by the iisnode module -->
            <add name="iisnode" path="app.js" verb="*" modules="iisnode" />
        </handlers>
    
	<!-- Rewrite rulex excerpted for brevity --> 
        
	<!-- You can control how Node is hosted within IIS using the following options -->
        <!--
        <iisnode      
            nodeProcessCommandLine="%systemdrive%\node\node.exe"
            maxProcessCountPerApplication="4"
            maxConcurrentRequestsPerProcess="1024"
            maxPendingRequestsPerApplication="1024"
            maxNamedPipeConnectionRetry="3"
            namedPipeConnectionRetryDelay="2000"      
            asyncCompletionThreadCount="4"
            initialRequestBufferSize="4096"
            maxRequestBufferSize="65536"
            uncFileChangesPollingInterval="5000"
            gracefulShutdownTimeout="60000"
            loggingEnabled="true"
            logDirectoryNameSuffix="logs"
            maxLogFileSizeInKB="128"
            appendToExistingLog="false"
        />
        -->
    
    </system.webServer>
</configuration>

Note that there's only one required setting, which enables the iisnode handler and points it at app.js. The sample template includes an example section (commented out) which shows additional configuration options.

Playing nicely with existing Javascript files

Since we don't want to interfere with our client-side .js files, we need to tell the handler how to distinguish between client-side and server-side .js files. Tomasz Janczuk, developer of iisnode, has posted a lot of information about how configuring iisnode using web.config, including a few ways to handle that:

  • Point the handler at a specific file like the sample above, which tells iisnode only to handle requests for app.js
  • Use another file extension, like .njs, for server-side .js files. In that case, you'd use path="*.njs"
  • Use a <location> element to specify that iisnode should handle all .js files in a specific directory

Note: Remember that due to the web.config hierarchy and inheritance, so you can make system-wide settings that relate to iisnode, at the app level, etc.

Simple example: Including a Node endpoint in an existing ASP.NET MVC Application

With the above in mind, it's pretty simple include some Node goodness in an existing ASP.NET MVC application. Here's how:

Ensure the project is using the IIS Express server (rather than the ASP.NET Development Server, a.k.a. Cassini)

In order to take advantage of iisnode, you'll need to switch your project's server to IIS Express if you haven't already.

IIS Express is a lightweight, self-contained version of IIS optimized for developers - it's included with WebMatrix and Visual Studio 2010 SP1, or you can install it individually using Web Platform Installer. It gives you most of the benefits of running in the full IIS environment, but runs as an application under user permissions rather than a full system-level server. We interviewed Vaidy Gopalakrishnan about IIS Express on Herding Code 89 if you'd like to know more.

Listen: Herding Code 89: Vaidy Gopalakrishnan on IIS Developer Express

Node: You can (of course) develop your project against the full IIS server and take advantage of iisnode. In most cases, though iisnode is a better choice for development.

Switching your project to use IIS Express is incredibly simple: right-click the project and select "Use IIS Express..." then confirm the resulting dialog.

2011-10-25 16h22_12

 

Configure the iisnode handler in web.config

I listed a few options for incorporating node into an application above. In this case, I've decided to add a Node directory to the project and use the <location> element to target it. To do that, I included the following directly under the <configuration> node:

<location path="Node">
  <system.webServer>
    <handlers>
      <add name="iisnode" path="*.js" verb="*" modules="iisnode" />
    </handlers>
  </system.webServer>
</location>

Next, I added a Javascript file to that Node directory (right-click the folder, Add New Item, JScript File (yes, JScript is a silly name)). I played with some different, more complex examples, but in the end I decided to keep it simple and just return HTML (with apologies to GLaDOS):

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write('<html><head><link href="/Content/Site.css" rel="stylesheet" /></head><body>');
    res.write('<h1>Are you still there?</h1>');
    res.write('<p>');
        res.write('We are pleased that you made it through the final challenge where we pretended we were going to murder you. We are very very happy for your success. ');
        res.write('We are throwing a party in honor of your tremendous success. Place the device on the ground, then lie on your stomach with your arms at your sides. ');
        res.write('A party associate will arrive shortly to collect you for your party. Make no further attempt to leave the testing area. ');
    res.write('</p>');
    res.write('<p>');
        res.write("Proceed to test chamber " + process.env.PORT);
    res.write('</p>');
    res.end('</body></html>');
}).listen(process.env.PORT); 

Note that near the end we return process.env.PORT, which will return the port that Node is listening on. Want to guess which one? You'll never guess...

2011-10-26 10h13_41

Did you guess it? Sorry, it was a trick question - iisnode is apparently communicating with Node over a named pipe rather than a port. Neat.

Note 1: This is an incredibly simple example, and it doesn't show off what iisnode is really built for. Some more compelling, really world examples of integrating into an ASP.NET site might include running a backend service (socket I/O, chat, XMPP), providing a service to handle Ajax requests, or otherwise taking advantage of Node's asynchronous, evented model. If I were to do anything more complex, I'd want to take advantage of the rich Node module ecosystem rather than writing everything from scratch. I decided not to do that here because I want to focus on the getting started scenario. If time permits, I'd love to do a follow-up that's more advanced.

Note 2: While this is mostly a completely standalone page that's oblivious to the surrounding ASP.NET MVC site, it doesn't need to stay that way. I did reference the site's stylesheet, and there's no reason I couldn't be calling into the database, any server-side services, etc.

Development Environment support and Logging

There's no server-side debugging support for Node in Visual Studio or WebMatrix (yet - here's hoping they add it). There are some development environments available that do have that, including:

However, IIS does provide failed request tracing and logging, both of which are helpful for simple debugging. I'll break the code in my index.js sample above by requiring a (missing) cake module on first line:

var cake = require('cake');

When I run this, I'll see an HTTP 500 error message page from IIS which tells me where to find my failed request tracing logs. In this case, failed request tracing isn't going to give as much info as the logs, but let's take a look.

2011-10-26 10h45_53

That directory contains a bunch of XML files with the request tracing logs. Opening the latest shows that I have a file not found error.

2011-10-26 10h56_13

Failed request diagnostics are really helpful for a lot of more complex scenarios, but in this case I've got a simple code error, and the Node logs will be a lot more helpful. Logging was automatically enabled by iisnode - to disable or configure logging, see the commented-out <iisnode> element in the first web.config sample. The default location for the index.js logs is in a /Node/iisnode.js.logs directory. There's one log file in it - 0.txt - and it tells me what went wrong:

node.js:203
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: Cannot find module 'cake'
    at Function._resolveFilename (module.js:334:11)
    at Function._load (module.js:279:25)
    at Module.require (module.js:357:17)
    at require (module.js:368:17)
    at Object.<anonymous> (C:\Users\Jon\Documents\Jon-Share\Projects\NodeMusicStore\MvcMusicStore\MvcMusicStore\Node\index.js:1:74)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.<anonymous> (module.js:470:10)

Wrapping Up

This is just scratching the surface here, and the example's trivial. As I mentioned earlier, I think the real power of Node is in taking advantage of its event-driven, asynchronous model, and I'm interested to see how smart people like you will take advantage of the fact that you can now get it up and running - inside your ASP.NET applications, even, if you want - in just a few minutes.

Taking a look at the HTML5 video use in the Bing video homepage

I've always liked the pictures on the Bing homepage. In late September, they started occasionally replacing the picture with an HTML5 video. The Bing team blogged about it, and included an interesting video from the managing editor for the Bing homepage that talks about how they select photos and why they're going to start adding the occasional video backgrounds.

I've been interested in HTML5 video implementations since I first started playing with them in the Firefox 3.x nightly builds. Since the Bing page was presumably designed to handle "industrial strength" use - many browsers, high performance, bandwidth consideration - I thought I'd peek under the hood and see how things were set up.

Note: While I also work for Microsoft, I don't have any inside info on how or why they set things up as they did - I'm just some random guy on the internet for the duration of this post.

The homepage changes every day, but you can click back to previous homepages using the back arrow in the bottom right:

2011-09-28 13h34_51

HTML5 Video as a design element

The obvious use of HTML5 video is in the traditional video player experience, like the YouTube HTML5 video player. It's interesting to see <video> used as a design element here, just like the good old <img> tag. It's not content to be viewed, it's not essential to the page, but it's a nice touch - providing it's used subtly and tastefully, which is definitely the case here. I'm this kind of thinking providing it doesn't adversely affect the user experience in other ways, so I'll look at that more next.

HTML5 Video tag overlaying an image

First, I noticed that the <video> tag is on top of a <div> which has background image set via CSS. I think this is a good idea for a few reasons:

  • Nice preload experience for the video
  • Nice fallback experience if the video can't be shown

Nice preload experience for the video

Since the image is the first frame of the video, the user experience is really smooth - a nice image is shown immediately, and the when the video loads and plays, it's a very smooth transition.

Nice fallback experience if the video can't be shown

In case the video doesn't load, can't be displayed, Javascript is disabled, etc., the image background is just fine as a fallback.

This wouldn't work well if the video were essential content. In that case, I'd use embedded content in the <video> tag to fallback in the case the video tag can't be rendered. Using embedded content for is a subject for another post, but the the idea is that you can put content inside a tag, and browsers will automatically fall back to the embedded content if they can't display the parent, like this:

<!-- Example - not in the Bing source -->
<video>
    <source src="video.ogg" type="video/ogg" />
    <source src="video.mp4" type="video/mp4" />
    <embed  src=http://site.com/video/player 
            type="application/x-shockwave-flash" 
            allowfullscreen="true">
       </embed>
</video>

So in this case, we've got a <div> (background image set via CSS) which contains a <video> tag:

<div style='height: 472px;' id='bgDiv'>
    <video id='vid' 
           onended='VM.play();' 
           preload='auto' 
           loop='true' 
           autobuffer='true'
           width='956' 
           height='512'>
    </video>
</div>

The #bgDiv background is set to the background image: http://www.bing.com/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US56140151.jpg

Video Source

Due to some conflicts in codec licensing, there's no one video codec that will work on all browsers. Cross-browser HTML5 video requires several media source types. There are two ways to handle the multiple source issue:

Using any number of <source> elements, as shown below, the browser will choose automatically which file to download. Alternatively, the javascript canPlay() function can be used to achieve the same. The "type" attribute specifies the MIME type and possibly a list of codecs, which helps the browser to determine whether it can decode the file.

So the declarative way to handle this is to nest multiple source elements in the video, like this:

<video poster="movie.jpg" controls>
        <source src='movie.webm' type='video/webm; codecs="vp8.0, vorbis"'/>
        <source src='movie.ogv' type='video/ogg; codecs="theora, vorbis"'/>
        <source src='movie.mp4' type='video/mp4; codecs="avc1.4D401E, mp4a.40.2"'/>
        <p>This is fallback content</p>
</video>

That's what I'm more used to seeing. The Bing implementation use the other, imperative option. When loading, it uses Javascript to query for supported video types and loads based on the result. First, the three main video types are loaded into an array:

var g_vid = [
    ["video\/webm; codecs=\"vp8, vorbis\"", "\/az\/hprichv\/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.webm"],
    ["video\/ogg; codecs=\"theora, vorbis\"", "\/az\/hprichv\/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.ogv"],
    ["video\/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"", "\/az\/hprichv\/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.mp4"]
];

Next, an onload function for the video element decides which source to load:

this.sa_vid_ld = function (e) {
    try {
        a = _ge("vid");
        if (this.Loaded || _w.g_vid == undefined || _w.g_vid == null || a == null) return;
        var d = _w.g_vid;
        sj_be(a, "canplaythrough", e ? e : VM.fade);
        sj_so(a, 0);
        a.width = VM.Constants.VideoWidth;
        a.height = VM.Constants.VideoHeight;
        for (var b = 0; b < d.length; b++) if ( !! (a.canPlayType && a.canPlayType(d[b][0]).match(/^(probably|maybe)$/i))) {
            a.type = d[b][0];
            a.src = d[b][1];
            c = sb_gt();
            break
        }
    } catch (f) {
        HPV_er(f, "Load")
    }
}

Note the interesting match on canPlayType - since browsers may rely on external codecs, calling canPlayType on a codec type can return probably, maybe, or an empty string.

Browser sniffing

There's definitely some server-side browser sniffing going on here. Normally I frown on that kind of thing, but for high-volume bandwidth-sensitive search engine home pages, all bets are off. View source on http://google.com - it's not pretty either, and I'm certain smarter people than me have looked at both of these home pages in great detail.

I think this is similar to database denormalization (assuming you're into normalized databased) - a general rule applies under general conditions, but the general rules go out the window in special circumstances. Normally I'd call web developers crazy for writing custom (non-jQuery) selector logic, but Bing and Google both eschew jQuery.

I compared the HTML for the Bing homepage when using IE9 and IE9 with a IE6 user-agent.

2011-10-12 01h53_53

When browsing with an IE6 user-agent, Bing doesn't send the <video> tag. Additionally, it sets a g_hasVid boolean variable so there's no attempt to determine video capabilities and set the source.

Again, while this would normally get me worked up, I can see the wisdom in minimizing the content written to the browser.

Looping and HTTP 304

The <video> tag is set to automatically loop. Note the loop="true" in the video tag below:

<div style='height: 472px;' id='bgDiv'>
    <video id='vid' 
           onended='VM.play();' 
           preload='auto' 
           loop='true' 
           autobuffer='true'
           width='956' 
           height='512'>
    </video>
</div>

Profiling the page, though, I see that there are continued requests for the video. The page is correctly using a HTTP 304 (not modified) response, so that the locally cached video is reused:

URL

Method

Result

Type

Received

Taken

Initiator

Wait

Start

Request

Response

/fd/ls/GLinkPing.aspx?IG=8226ea3583704baaac8a91619295f16b&ID=SERP,5033.1

GET

200

image/gif

250 B

171 ms

<img>

1981

78

78

15

/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US56140151.jpg

GET

200

image/jpeg

80.01 KB

266 ms

background-image

2620

0

47

219

/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.webm

GET

200

video/webm

1.58 MB

1.03 s

 

2636

0

62

968

/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.webm

GET

304

video/webm

219 B

16 ms

 

13915

0

0

16

/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.webm

GET

304

video/webm

219 B

< 1 ms

 

19016

0

0

0

/az/hprichv/?p=OctLeaves_Artbeat_PF-FH103-79_EN-US.webm

GET

304

video/webm

219 B

15 ms

 

24102

0

0

15

Posted by Jon Galloway | 1 comment(s)
Filed under:

ASP.NET website redesign beta: What's changed, why, and how you can make it better

We're happy to announce the beta release of something we've been quietly working on for a while now: a redesign for the ASP.NET website (http://asp.net). You can browse directly to it at http://beta.asp.net, or if you're on the http://asp.net site you can click on the "Try the NEW beta site" link in the header.

beta.asp.net - home

Goal: Make it easier to find useful information

Scott Hanselman listed some of the goals of this new design in his post:

    • A newer Information Architecture (IA) that scales with different types of content. Trying to get you somewhere useful quickly.
    • Content organized into relevant topic areas (Overview, Videos, Tutorials, etc.) to make information easier to find and to learn a technology.
    • Improved on boarding experience – Developers new to ASP.NET should find it easier to get started and download what they need.
    • Important Samples and Tutorials are positioned prominently in the structure of the site so that they are easier to find.
    • Textual Tutorials are as important as videos - We've heard people want text tutorials more than videos, so we're finding balance between these two kind of content.
    • Improved Social Integration – Community info, pulling from Twitter, Facebook and blogs.
    • A less cluttered user experience to get you where you need to go in fewer clicks.
    • Open Source and Samples - We're looking for new ways to showcase great open source projects and excellent samples.

The main point is in trying to make it easier for you to find useful content. ASP.NET's capabilities have grown quite a bit over the years, and there's a ton of content spanning technologies (ASP.NET Web Forms, ASP.NET MVC, ASP.NET Web Pages), skill levels (getting started through advanced), content types (reference material, tutorials, blogs).

While it's tempting to focus on the home page, the goal is more apparent when you drill into the content. For instance, if you're looking for information about Models in ASP.NET MVC, the existing site has historically made you play hide and seek a bit. We've recently been working to provide some structure around the content, as you can see in the Learning Resources section on http://asp.net/mvc.

asp.net site - MVC page

The new beta.asp.net site goes a lot farther, elevating that content outline structure more directly into the site:

beta.asp.net - Content page

There was a time, not all that long ago, when adding a new "page" to the site required adding a new page to the site. As in, adding any content required development and deployment. In May 2010, I posted about a site redesign which started the work of trying to better organize and surface content, but as we weren't fully on a content management system then it wasn't as possible to really reorganize content as much as we wanted. Now that the content's managed by a content management system, we can not only create and manage content more quickly, we can move it around.

A fresher design

I'm happy to see a much cleaner, clearer, and more modern design. As I just mentioned, we last updated the site 17 months ago. For a comparison, here are side-by-side shots of the home page comparing the previous, current, and beta designs.

Old:

ASP.NET Home Page - Circa May 2010

Current:

ASP.NET Home Page (circa Oct 2011)

Beta:

beta.asp.net - home

And here's how the ASP.NET MVC content has evolved over time (screenshots showing more drilldown with each release).

Old:

Current:
asp.net site - MVC page
Beta:
beta.asp.net - Content page

Community content

I've always wished we did a better job of surfacing our community content, and I'm very happy with the progress on http://beta.asp.net/community. I'm going with the tiny screenshot here since there's a lot of content, but I love how this shows:

  • Daily Spotlight
  • Article of the Day
  • News
  • Community Blogs
  • Microsoft Blogs
  • Events
  • Twitter
  • Forum highlights
  • New Wiki Articles
  • Community Samples
  • Control Gallery updates

beta.asp.net - community page

Feedback, plz!

Okay, I told you what we hoped to accomplish. How's we do? This is a beta, and we're honestly, earnestly seeking your feedback.

The best way to give your feedback (much better than a blog comment!) is to post your feedback on the dedicated UserVoice forum for the ASP.NET website.

Posted by Jon Galloway | 3 comment(s)
Filed under: ,

ASP.NET MVC 4 Overview - Part 2: Default template changes and Adaptive Rendering using Viewport and CSS Media Queries

This is Part 2 of a series overviewing changes in ASP.NET MVC 4. In Part 1, we looked at installation and new options in creating a new project. In Part 2, we'll look at changes to the default project template and how it uses adaptive rendering to optimize the display for the end user's browser dimensions.

When we left off, we'd just run through the File / New Project / New ASP.NET MVC 4 Web Application / Internet Application and created a new project. Up through this point, the process has looked pretty similar to the ASP.NET MVC 3 experience with a few new options.

When we run the application, though, things start looking significantly different. I'll compare what's different, then explain why this will help you build mobile-ready sites more effectively.

Review: The ASP.NET MVC 3 template

Just in case you need a reminder, the ASP.NET MVC 3 default template looks like this:

The astute ASP.NET MVC historians among you will note that the ASP.NET MVC 3 default template was very similar to the default template in ASP.NET 1 and 2, with two very subtle changes:

  • The corners on the boxes are rounded (subtle - but nice - improvement using CSS 3 border-radius)
  • Viewing source source reveals that the page is constructed using HTML5 semantic elements (header, nav, section, footer) which are backwards compatible due to use of the Modernizr library

Overall, I think it's fair to say that the ASP.NET MVC default template has been functional but austere, and perhaps a bit dated. No more!

The ASP.NET MVC 4 Default Template: Updated design

There's a completely new design here. It's still relatively simple, but it actually looks like a web page you might see on the public internet.

The obvious - new colors and fonts

This design actually looks like an actual web designer was involved, which is nice. The fonts have improved, too. For example, the preferred body font has changed from Trubuchet MS to Segoe UI.

Look, Mom! Three columns!

I'm personally happy to see some columns in the default template without using a grid system or a table (a.k.a yesteryear's grid system). While you may immediately remove this page most of the time, I'm glad that folks can see a nice, clean implementation of columnar layout.

Hmm... images?

The previous templates have always been CSS-only designs with no images, and I was a little surprised to see images in this default template. I talked to Matthew Osborn, an ASP.NET team member who worked on this new design, at the BUILD conference in September. He told me that the tradeoff there was that doing anything fancy with the CSS - such as creating the numbered bullets using border-radius - would have resulted in CSS that wasn't very reusable. On the other hand, the images are easily removable or replaceable. After talking to him a bit, this makes good sense to me.

Adaptive Rendering using CSS Media Queries

While the new visual design is welcome and interesting, it'll probably get replaced in most real applications. The really interesting bit here is the adaptive rendering. To see how what that means, think about how the ASP.NET MVC 3 (and below) default templates look in a mobile browser (or in this case, the Windows Phone Emulator).

The design's clearly not optimized for a mobile device, and zooming in so you can read the tiny print doesn't help that much since the text doesn't reflow.

Let's take a look at the ASP.NET MVC 4 default template in a mobile browser:

What's immediately obvious is that this page is intelligently scaled to the screen size of the mobile device. Rather than just scaling the page down (shrinking text and all), the page is redrawn so that it's usable at in the device's dimensions.

What might not be immediately obvious is that the page layout actually changes subtly at this smaller size to optimize for the new dimensions. Some examples from the header area:

    • The logo is aligned left in the desktop view, centered in the mobile view
    • The registration / login links are aligned to the top right in the desktop view, and are both centered and dropped below the logo
    • The Home / About / Contact links are aligned

Scrolling down further, you can see the other simplifications to the mobile view to tighten it up and maximize the screen real estate.

While the changes are subtle, they make a difference. Examples:

  • The round bullet icons in the "We suggest the following" list are removed in the mobile view
  • The footer is centered, and the Facebook / Twitter logos are  replaced by small text

Adaptive Rendering

These templates are using what's known as adaptive rendering to automatically scale the page depending on page width.

Note that I didn't say that the application is scaling the page by guessing if the user's on a mobile device based on headers or other clues. That's known as browser sniffing, and it's generally frowned - it's error prone, and when you guess wrong you irritate your users. Instead, this page is making use of two commonly supported browser features, the viewport meta tag and the use of CSS media queries.

The Viewport Meta Tag

The majority of web pages have been created without any thought to how they'll appear in smaller form factors, and mobile browsers have long struggled with guessing how best to display them. Designs which are primarily focused on semantically structured textual content can be reformatted to make the text readable, but sites with rigid (brittle?) visually oriented designs don't reformat well at all and need to be handled with zooming and panning.

Since the majority of websites weren't designed to scale well, when mobile browsers have to guess how to render your page they'll generally fail safe and go with the zoom and pan style rendering. The solution to this problem is to use to tell the browser what your design dimensions are, so it doesn't have to guess.

Often, Viewport tags are only used in pages which are specifically designed for small form factors, based on browser sniffing or user selection (see the mobile section of my post on about the Microsoft PDC 2008 site for an example). In this case, you'd see a Viewport tag that looks something like this:

<meta name="viewport" content="width=320">

This works for mobile-specific views, but doesn't adapt to larger sizes well.

A better solution is to design your CSS to scale well at all sizes (more on that in a second), then tell the browser that the Viewport is whatever the device supports. Fortunately, that's pretty easy:

<meta name="viewport" content="width=device-width">

Notes for further study on Viewport:

Adaptive styles using CSS Media Queries

Okay, we've told browsers that our page will look brilliant when scaled to the current device's screen dimensions. That's a bold claim - how will we follow through on that promise? The answer here is CSS Media Queries.

CSS Media Queries allow you to target CSS rules at particular media (display) features. From the W3C spec (er... candidate recommendation):

HTML4 and CSS2 currently support media-dependent style sheets tailored for different media types. For example, a document may use sans-serif fonts when displayed on a screen and serif fonts when printed. ‘screen’ and ‘print’ are two media types that have been defined. Media queries extend the functionality of media types by allowing more precise labeling of style sheets.

A media query consists of a media type and zero or more expressions that check for the conditions of particular media features. Among the media features that can be used in media queries are ‘width’, ‘height’, and ‘color’. By using media queries, presentations can be tailored to a specific range of output devices without changing the content itself.

TL;DR summary: whereas with CSS2 you could use target media types like screen and print, with media queries you can target a screen display with a certain min or max width.

Remembering that CSS rules are evaluated from top to bottom, this means that we can apply general rules at the top of our CSS file and override them with rules specific to smaller displays later in our CSS, surrounded by a media query so they won't be applied by browsers in larger form-factor displays.

In the following very simple example, the background will be blue on displays wider than 850px and red on displays narrower than 850px.

body {background-color:blue;}
@media only screen and (max-width: 850px) {
    body {background-color:red;}
}

That's exactly how the CSS in the default ASP.NET MVC 4 template works: general rules followed by mobile form-factor rules guarded by an 850px max-width media query.

If you've been paying attention, you'll have guessed that we can test this out just by resizing a desktop browser narrower than 850px, and that guess would be correct:

If you've got ASP.NET MVC 4 Developer Preview installed (and I think you should) you can easily test this out: create a new project, run it, and resize the browser.

Notes for further study on CSS Media Queries:

How does this new template help me create mobile-ready web applications?

As I pointed out earlier, the ASP.NET team knows that you'll be largely replacing this design with one that works for your specific application. Hopefully this design is closer to something that you might use, but I'm guessing that your logo will not be "your logo here."

I see this new design helping in two ways:

  • It provides a workable starting point
  • It shows some examples that you can hopefully leverage and extend

A workable starting point

Starting with a completely empty page when you begin an application wastes your time in many cases. Rather than focusing on the needs of your application, you're stuck with trivia like setting up some standard CSS resets (clearing HTML and body padding, setting some standard float rules, etc.), resetting link styles, picking some halfway decent fonts and looking up the viewport and media query cheat codes you need to scale the page properly. This is a diversion from solving the problem that caused you to hit File/New to begin with.

Instead, this template will (hopefully) let you get started with a workable design and layout, focus on your business problem, and focus on the design when it makes sense for you.

If you want to start with an empty slate, you can either use the Empty project template (described in the previous post) to start with a minimal project, or you can quickly delete images and styles that you don't need.

Examples

This sample layout, while pretty simple, solves a lot of problems developers are forever fighting:

  • Headers with left and right alignment
  • Handling multiple columns (without resorting to tables or grid systems)
  • Setting style rules that effectively handle differing browser resolutions

So the next time a developer tells me that columns are too hard in HTML and CSS or that it's too much work to set up a layout that adapts to small screen sizes, I'll tell them to open up a new ASP.NET MVC 4 application and take a look.

That wraps up Part 2 of our ASP.NET MVC 4 overview looking at improvements to the default template for adaptive rendering. In Part 3, we'll take a look at using Display Modes to customize output based on server-side logic.

More Posts