Scott Hanselman

Conditionally Serve Files Statically or Dynamically with HttpHandlers

February 01, 2007 Comment on this post [3] Posted in ASP.NET | HttpHandler
Sponsored By

I have some static files - RSS XML in fact - that have been served by IIS as static files for a while. I consider them permalinks, and I don't want to change that for now, but I wanted to do some testing with FeedBurner (similar do what I did before with FeedBurner in DasBlog) letting them serve the RSS for a while, gathering statistics. If it went well, I'd go with FeedBurner full time for those files - but not all.

So, given a directory with: foo.xml, bar.xml, bat.xml and others all served statically by IIS, I wanted a quick and dirty way to maintain the permalinks while handling a few of the files dynamically, and a few as redirects to FeedBurner.

There's a number of ways to solved this depending on your version of IIS and ASP.NET; here's an easy way, and the way I'm doing it now.

By default IIS will serve XML files as static files with the text/xml mime type and ASP.NET will never hear about it. As XML files aren't handled by ASP.NET, first I need to configure IIS to pass all requests for XML files for this VDIR to ASP.NET. Do this from the Configuration button under Home Directory in the Properties pages of the app/vdir. I've pointed ".xml" to aspnet_isapi.dll as seen in the figure at right.

Note that you need to be explicit if you want IIS to check if the file exists. For example, if foo.xml is a real static file on disk, but bar.xml is going to be dynamically created, don't select "Verify that file exists." Setting this checkbox wrong is the #1 developer-error that you'll hit when creating HttpHandlers to handle custom extensions.

Next I'll add a handler in web.config for *.xml (or just foo.xml, etc, if I want to be more restrictive).

   1:  <httpHandlers>
   2:  <add verb="GET" 
   3:  path="*.xml"
   4:  type="Foo.Redirector,FooAssembly"
   5:  />
   6:  </httpHandlers>

Now I'll create a VERY simple HttpHandler that will fire for all .xml files (or just the ones you want, if you only associated a few files in your web.config.

This is your chance to:

  • Redirect elsewhere
  • Dynamically generate the file they asked for
  • Pick up the file off disk and serve it statically

The example below checks to see if the UserAgent requesting the files foo.xml or bar.xml is FeedBurner. (You could check other things of course, like IP subnet, etc.) If it isn't FeedBurner's bot, we currently redirect them temporarily with an HTTP 302. There's commented code for a permanent redirect, which RSS Readers respect, that would cause the client to update their bookmarks and never return. For now, I'll do a temporary one.

   1:  using System;
   2:   
   3:  namespace Foo
   4:  {
   5:      public class  Redirector : System.Web.IHttpHandler
   6:      {
   7:          void System.Web.IHttpHandler.ProcessRequest(System.Web.HttpContext context)
   8:          {
   9:              string userAgent = context.Request.UserAgent;
  10:              if (userAgent != null && userAgent.Length > 0)
  11:              {
  12:                  // If they aren't FeedBurner (optional example check)
  13:                  if (userAgent.StartsWith("FeedBurner") == false)
  14:                  {
  15:                      string redirect = String.Empty;
  16:                      string physicalpath = System.IO.Path.GetFileName( 
context.Request.PhysicalPath).ToUpperInvariant();
  17:                      switch (physicalpath)
  18:                      {
  19:                          case "BAR.XML":
  20:                              redirect = "http://feeds.feedburner.com/Bar";
  21:                              break;
  22:                          case "FOO.XML":
  23:                              redirect = "http://feeds.feedburner.com/Foo";
  24:                              break;
  25:                      }
  26:                      if (redirect != String.Empty)
  27:                      {
  28:                          context.Response.Redirect(redirect); //temporary redirect
  29:   
  30:                          //context.Response.StatusCode = 
(int) System.Net.HttpStatusCode.MovedPermanently; //permanent HTTP 301
  31:                          //context.Response.Status = "301 Moved Permanently";
  32:                          //context.Response.RedirectLocation = redirect;
  33:                          return;
  34:                      }
  35:                  }
  36:              }
  37:              context.Response.ContentType = "application/xml";
  38:              context.Response.TransmitFile(context.Request.PhysicalPath);
  39:          }
  40:   
  41:          bool System.Web.IHttpHandler.IsReusable
  42:          {
  43:              get { return true; }
  44:          }
  45:      }
  46:  }

If they ARE FeedBurner, that means their bot is returning to get fresh data from the foo.xml or bar.xml files. If so, we call the new ASP.NET 2.0 TransmitFile API, that supplements/improves on the earlier WriteFile. Transmit file doesn't buffer to memory and solved a number of problems seen when writing out files and buffering.

We also fall to this default code path if any other XML file has been requested, if that file is hooked into ASP.NET via the web.config. In my example, *.xml is hooked up, so all other requests end up in the TransmitFile API.

TransmitFile doesn't pass the request back to IIS, as some folks believe, nor does it handle caching for you. If you need that support you'll need to write it by following the HTTP spec and handling the headers yourself.

To recap:

  • Tell IIS to pass handling of your extension to ASPNET_ISAPI
  • Map files or extensions to Assembly Qualified Names in the web.config httpHandlers section - i.e. What class handles what files dynamically?
  • Create, redirect or serve your files

I'll try to writeup some other ways to solve the same problem, depending on what version of ASP.NET and IIS you're using. If you've got clever ways (there are many) leave them in the comments.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Making your Application Automatically Update Itself

January 31, 2007 Comment on this post [27] Posted in Programming
Sponsored By

I've always thought it was the height of classiness when an application lets me know that there's a new version available. Even little applications with no installer like Lutz's Reflector update themselves automatically.

There's lots of ways to implement an automatic update check in your application, and many products that say they'll do it automatically.

From my point of view, there's a number of levels of "coolness" in auto-updating. Now, all this assumes you're NOT using ClickOnce.

Cool:

  • Add a "Check for Update" menu that just launches the default browser like www.foo.com/update.aspx?version=3.3.4.4 where 3.3.4.4 is your own Main Assembly Version. Then the requested page just lets them know if they've got the latest or not.
    • You can get your app's version number via System.Windows.Forms.Application.ProductVersion() or System.Reflection. Assembly.GetExecutingAssembly(). GetName().Version.ToString(). Whew!

Cooler would be:

Cooler still would be:

  • Add a "Check for Update" menu that retrieves via a programmatic HTTP GET some XML from www.foo.com/update.aspx?version=3.3.4.4. Then report INSIDE your app if the user needs to upgrade, THEN ask them if they want to download the current version. If they say yes, do so, then close your app while shelling out to run the new updater/setup.
    • Bonus points for checking once a day/week/month for updates, silently, gracefully.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Upcoming Events Jan/Feb 2007

January 31, 2007 Comment on this post [1] Posted in Corillian | Speaking
Sponsored By

Here's a few upcoming local events that you might be interested in. I think that being a good developer is a start, but getting involved in the local developer community - whatever language or OS you're into - really helps make a technologist more well-rounded.

  • Tonight at 6:30pm at the Microsoft Portland Office Jason Mauer will be talking about XNA Game Studio Express. I'm watching Z tonight so I'll stop by to give away a Wrox Box and hang out until he cries.
    • "XNA is the future of game development with all the comforts of managed code, and it's here today for the PC and Xbox 360. Come see how much easier XNA makes it to build a game for Windows, and run it on your 360 in the living room."
  • Tues, Feb 6th at 7:30am at the Governor Hotel in Portland, I'll be on a panel discussing "Why Services Oriented Architecture (SOA) is Important to Your Product Success" with Joe Daly, Director of SOA at Intel and Gordon Ferlitsch (my old boss), VP of Technology at Transcore. Should be a spirited (!) talk and you'll still make it to work on time.
  • Saturday, Feb 10th at 10:00am at Willamette University in Salem, there's an event that's open to the public on Future Potential in Computing. While this event is primary focused on getting college students to consider a career in geekery, check out folks (plus me) that are on the panel and presenting. It might be worth the short drive down from Portland and making a day of it, we are. Don't tell anyone I only have a B.S. in Software Engineering.
    • Paul E. McKenney - Distinguished Engineer at IBM
    • Kathleen O'Reilly - Computer Animator from LAIKA
    • Karen Ward, Ph.D. - Assistant Professor of Computer Science in UP's School of Engineering
    • Mike Bailey, Ph.D. - Professor of Computer Science at Oregon State
  • Thu, Feb 15th at 11:30am at Microsoft's Portland Office, Stuart Celarier and I will be talking about CardSpace and the Laws of Identity. Stuart has created an excellent deck on this topic with some great Beyond Bullets designs that really lend themselves to the topic. Hopefully I'll have some demos of DasBlog running CardSpace along for the ride.

See you there!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Finding Free Radio Station Frequencies for my iPod

January 29, 2007 Comment on this post [5] Posted in Musings
Sponsored By

Well, my wife's iPod actully. I've still got it on my To-Do list to get my wife's Honda Civic Hybrid hooked up with proper iPod integration, but until then she'll have to use an FM Transmitter to listen to her tunes. It's always such a hassle to find a decent free frequence to transmit on.

Travis pointed out this incredibly useful Radio-Locator that finds the best radio frequencies in your area for this very reason. There's also amore limited Canadian Radio Frequency Search and International Search.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Another Way to Replace Start Run - Enso Launcher

January 25, 2007 Comment on this post [12] Posted in Reviews | Tools
Sponsored By

Stephen Nelson turned me on to Humanized Software's "Enso Launcher" (blog) earlier today, and I've been playing with it all evening. I've been on a quest to replace Start|Run for years (podcast). I've also done a lot of work in UI and UX and these guys are definitely fans of Jef Raskin's Humane Interface for good reason. Not just because Jef was brilliant - but also because they worked directly with him. The Enso Launcher is dedicated to Jef.

As I write this I notice that Enso was written up in the WSJ by Walt Mosberg today. Good PR team.

These guys have two products so far, one, a universal spell-checker called Enso Words with a very clever overlay interface. Right now I use an autocorrecter called Universal Autocorrect. Personally I think that US$40 is twice as expensive as it warrants.

However, the really interesting application in their Enso Launcher, which is oddly more useful, but reasonably priced at US$24.95. It's not quite as fast and intuitive as the Holy Grail - QuickSilver for Windows, but it's absolutely clever enough for you to download and try out.

There's a number of folks who are fervently against the Caps Lock key. Rather than suggesting that we rip the key off our keyboards, Enso Launcher uses it as its one-and-only hotkey.

Good Stuff

  • You hold down Caps Lock, an overlay appears, you start typing, then release Caps Lock. Sounds god when you type it, but in practice, it's kind of a tricky maneuver. For example, hold Caps Lock with your pinky, Type "gog", then without letting go of Caps Lock, press Tab with whatever free finger you have, mine is the left ring finger, then type the search term you want, then let go of Caps Locks. It's a bit of a dance. I'd prefer NOT to have to hold Caps Lock, or be able to configure the "start" and "end" events, like "Ctrl-Space" to start and "Enter" to end the command.
    • There is an alternative "lock-on"command, but it's (to me) very hard to to fast. "You can press down Caps Lock, then press down Alt, then release Caps Lock, then release Alt."
  • The calculate() command. If you have some text like 2+2 in a text box, just select it and do Caps Lock, "calc", release, and the text in the textbox will be replaced with the answer. If there's an = at the end, the answer appears at the end.
  • The "go" command switches between running applications, but also within Tabs in FireFox and/or IE. So, I can type "go", Tab, "Han" and if I have my blog open in a tab, Enso will switch me there.

Bad Stuff

  • So far, I'm just not as fast with this as I am with SlickRun. Mostly because of the machinations of the left hand.
    • It really needs a "start" type "stop" command...holding down Caps Lock thing is, in itself, an implied Mode, and having to hold it down makes this tool that much harder to "sell" to my Wife and/or Parents.
  • No plugin model that I can see.
  • Runs pokey on my 3Ghz P4. Might be my crap video card.

I'd say that it's pretty darn impressive for a first product, and a 1.0 at that. One caveat, it doesn't officially support Vista (yet), but it works pretty well on my Vista machine with UAC turned of. Go get it, I suspect it's going places. It's this kind of out of the box UX thinking that I expected from Windows Vista.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.