A few weeks ago I was asking people if they’ve ever read an inspiring book about software development. There are many great books that are educational books. They show you how to build the latest whizz-bang application using the version 2.0 of the whizz-banger framework. An inspirational book, in my mind, transcends any specific technology and makes you think differently about how you approach your job.
Two books came up as answers time and time again.
Extreme Programming Explained: Embrace Change by Kent Beck
The original edition of this book was published in October of 1999 – one decade ago. Ten years! That’s like 100 years of software time. The book turned the rules of engagement for software development around. We don’t need big design up front. Software shouldn’t be hard to change – ever! Having an enterprise architect fly in to meet with the team 2 days of every week and draw arrows on the conference room whiteboard does more harm than good.
Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin
Clean Code is a great book. Many people told me the book has inspired them to be better developers. I personally didn’t find the book inspiring, but I did find it extremely thought provoking. So provoking I’ve read it twice and even put together a book club to meet and discuss the book with other people (we meet for lunch every other Thursday at the food court in the mall of Columbia, MD). Sometimes we agree with Uncle Bob, and sometimes not – but either way we have to think about we do every day from a different perspective.
What books would you add to the list?
I spent a few hours on a failed experiment recently, but one concept that outlived the spike was how to make use of private extension methods. By private I mean the extension methods have a private access modifier and are only visible inside of a single class.
Sounds pointless, right?
Consider the code in the following class that is attempting to build multiple script tags out of the names of JavaScript files embedded as resources in an assembly.
public static class ScriptHelper { public static string AsyncUploadScripts(this HtmlHelper helper) { var scriptNames = new string[] { "Baz.Biz.js", "Bar.Foo.js", "Foo.Bar.js" }; return scriptNames .Select(name => _manager.GetWebResourceUrl(typeof(ScriptHelper), name)) .Select(url => String.Format("... src='{0}' ...", url)) .Aggregate(new StringBuilder(), (sb, tag) => sb.Append(tag), sb => sb.ToString()); } // ... }
That LINQ query is not pretty. Something with ON ERROR GOTO statements would be easier on the eyes.
I thought it would be nice if I could have descriptive names for the operations being performed. But, I didn’t want to create new extension methods for use outside the query.
Fortunately, extension methods as static private members work well inside the same class.
public static class ScriptHelper { public static string AsyncUploadScripts(this HtmlHelper helper) { var scriptTags = GetScriptResourceNames() .MapNamesToResourceUrls() .MapUrlsToScriptTags() .CombineScriptTags(); return scriptTags; } static string CombineScriptTags(this IEnumerable<string> tags) { return tags.Aggregate(new StringBuilder(), (sb, tag) => sb.Append(tag), sb => sb.ToString()); } static IEnumerable<string> MapUrlsToScriptTags( this IEnumerable<string> urls) { return urls.Select(url => String.Format("... src='{0}' ...", url)); } static IEnumerable<string> MapNamesToResourceUrls( this IEnumerable<string> names) { return names.Select(name => _manager.GetWebResourceUrl(typeof(ScriptHelper), name)); } static IEnumerable<string> GetScriptResourceNames() { return new string[] { "Baz.Bif.js", "Foo.Bar.js", "Zak.Wak.js", }; } // ...
The code is now in the junk pile, but the idea will stick with me forever … or at least until I switch to something else.
Seadragon is one of the new controls in the AJAX Control Toolkit. It gives you all the goodness of Deep Zoom using only JavaScript. The control toolkit is designed to work with Web Forms, but the underlying Seadragon API is easy to use from anywhere.
If you want to see what Seadragon and DeepZoom can do, then check out some of the gigapixel images on SeaDragon.com (JavaScript), or browse my photos of Stockholm on DeepZoomPix (it uses Silverlight). Bonus points if you find the picture of Ayende with his head in the center of an ice sculpture.
Once you’ve put together your own image using Deep Zoom Composer, then all you need to use with MVC is the Seadragon Ajax Library hosted on Live Labs. Start with just a <div> in a view. Assuming you have the traditional MVC setup with a master page, it’s as simple as this:
<asp:Content ContentPlaceHolderID="MainContent" runat="server"> <h2>Seadragon</h2> <div id="container"></div> </asp:Content>
On my master pages I usually have a ContentPlaceHolder inside the <head> tag to inject script. With that in place, here is one way to get the Seadragon API loaded and bootstrap the viewer:
<asp:Content ContentPlaceHolderID="Scripts" runat="server"> <script type="text/javascript" src="http://seadragon.com/ajax/0.8/seadragon-min.js"> </script> <script type="text/javascript"> function init() { var viewer = new Seadragon.Viewer("container"); viewer.openDzi("/Content/sample.xml"); } Seadragon.Utils.addEvent(window, "load", init); </script> </asp:Content>
In openDzi, pass the path to the .xml or .dzi file you create with Deep Zoom Composer, and the library will take care of the rest. Of course, you’ll need to put all the rest of the files and folders the composer creates on your server, too. The viewer allows you to subscribe to events, create overlays, and add your own controls that respond to user input.
The last piece you’ll need is some styling for the div:
<style type="text/css"> #container { width: 500px; height: 400px; background-color: black; border: 1px solid black; color: white; /* for error messages, etc. */ } </style>
Impressive results with very little work!
App_Data, App_Code, App_Themes, and App_GlobalResources – we’ve come to love them over the years.
I was hoping the team could add a few more “special” folders to ASP.NET, but I don't think these will make it ...
App_Store – drop in an xml file with product descriptions and … presto! Instant e-commerce!
App_etizers – content you serve customers before they get to the main part of the site.
App_liances – will work with Azure, because cloud computing needs appliances.
App_endix – I'm not sure what this would do, actually. Perhaps I should remove it.
It sounds like an easy question -
“How do I make my ASP.NET MVC application generate lowercase URLs?”
Using lowercase URLs is an SEO best practice, and something you can easily enforce with a tool like URLRewrite. But, the action links generated by the MVC framework generally contain upper case letters (since controller and action names are generally PascalCased).
First, let me say that Graham O’Neale and Nick Berardi have already solved this problem in a foolproof manner. What I am trying below is a little bit easier, but does have one problem if you rely on route names. We always specify route names when using the MapRoute extension methods, but in actuality these names are rarely used to generate URLs in an MVC application. Instead, we generate URLs from controller and action parameters.
Nick and Graham both create a class derived from Route to lowercase the URLs returned by GetVirtualPath. Unfortunately, this means you can’t use the built-in MapRoute extensions method provided by MVC. For various reasons I wanted an approach that could somehow work with the built-in MapRoute methods. In looking for a solution I realized:
What I did come up with is to use a route decorator:
public class LowercasingRoute : RouteBase { public LowercasingRoute(RouteBase routeToWrap) { _inner = routeToWrap; } public override RouteData GetRouteData(HttpContextBase httpContext) { return _inner.GetRouteData(httpContext); } public override VirtualPathData GetVirtualPath(...) { var result = _inner.GetVirtualPath(context, values); if (result != null && result.VirtualPath != null) { result.VirtualPath = result.VirtualPath.ToLowerInvariant(); } return result; } RouteBase _inner; }
Then, after all the route registration code is finished, wrap the existing routes in the routing table with the LowercasingRoute.
private void DecorateRoutes(RouteCollection routeCollection) { for (int i = 0; i < routeCollection.Count; i++) { routeCollection[i] = new LowercasingRoute(routeCollection[i]); } }
Unfortunately, I lose all the route names using this approach. The RouteCollection class takes the route name we pass in MapRoute and stores it in a private dictionary and you never see it again. This isn’t an issue as most MVC applications will never use a route name to generate a URL, but it makes me nervous enough to wonder what to do next.
What do you think?
When .NET arrived on the scene it promoted the use of events and delegates to decouple code. Chris Sells had one of the best early stories on how it all works (.NET Delegates:A C# Bedtime Story)*:
Once upon a time, in a strange land south of here, there was a worker named Peter. He was a diligent worker who would readily accept requests from his boss. However, his boss was a mean, untrusting man who insisted on steady progress reports. Since Peter did not want his boss standing in his office looking over his shoulder, Peter promised to notify his boss whenever his work progressed.
For a few years I think we were all infatuated with events. We used them everywhere from the web to the desktop, and even in between. Looking around, you have to wonder if we went down the wrong road.
Consider the people who …
I’m thinking one day soon we will compare writing explicit event code to manual memory management.** Both will be low level details we don’t see in our everyday code.
If so, this will be quite a change from just a few years ago.
--
(*) The start of the story should sound familiar to anyone who worked with COM’s IConnectionPoint, which almost qualifies the story for an award in the horror category.
(**) If this means I never see the INotifyPropertyChanged interface in anyone’s code ever again, then I’ll welcome the new event overlords with open arms.
My latest article for MSDN Magazine appeared online and in print a few weeks ago. This article is about search engine optimization with the latest and soon-to-be released tools.
It wasn’t so long ago that SEO experts would lambast the .NET platform as poor choice of technology for SEO work, but much has changed just in the last year. While working on the article I exchanged some emails with Carlos Aguilar Mares, who sold me on features in the SEO Toolkit and the URL Rewrite extensions for IIS. The SEO toolkit will crawl your site and warn you about things the search engines don’t like to see - like bad redirects, missing ALT attributes, broken hyperlinks, and multiple canonical formats. You can use the toolkit to manage robots and sitemap files, and even find malware on your site. The URL Rewrite module can give you optimized and friendly URLs without giving up the performance benefits of kernel mode caching.
Things get even better next year with some of the features the ASP.NET and Visual Studio teams have in store. Read the article for more details.