Your Email Is (Practically) Your Identity
Posted: 2011/07/31 Filed under: pontification 7 Comments
I'm approaching this from a technical or practical perspective, more-so than a personal one. Karma, reciprocity, reputation, or similar are not pertinent to this discussion.
There’s a lot of confusion about what identity, on the internet, is. I contend that, for all practical purposes, your online identity is your email address.
Let’s look at some other (supposed) identification methods:
- Username – whatever the user feels like typing in
- OpenID – A guaranteed unique URL
- OAuth – some guaranteed unique token in the context of a service provider
What sets an email address apart from these other methods is that it’s a method of contacting an individual. In fact, it’s a practically universal method of contacting someone on the internet.
Consider, regardless of the mechanism you use to authenticate users, one returns to your site and wants to login… but can’t remember their credentials. This is not a trick question, obviously you have them enter their email address and then send them something they can use to recover their login information (a password reset link, their OpenID, their OAuth service provider, etc.). Regardless of the login mechanism, the lack of an associated email address will result in the loss of the account.

~7% of users on of StackID have forgotten their passwords at some point. The same ratio holds (OpenID instead of password) on Stack Overflow.
I find myself considering OpenID, OAuth, username and password combinations, and so on as “credentials” rather than “identities” conceptually.
Pontificating is all well and good, but how has this actually affected anything?
One of the first things I worked on at Stack Exchange (so long ago that the company was still Stack Overflow Internet Services, and the Stack Exchange product had a 1.0 in front of its name that it didn’t know about), was pulling in user email’s as part of authenticating an OpenID. There were two problems this solved, one was that user’s would accidentally create accounts using different credentials; a common trusted email let us avoid creating these accounts (this recently came up on Meta.StackOverflow). The second was that associations between site’s couldn’t be automated since Google generates a unique OpenID string for each domain a user authenticates to; finding related accounts based on email neatly worked around this wrinkle in Google’s OpenID implementation.

Adding those last two columns. Given a time machine we'd require them, but they're optional at time of writing.
Some of this predicament is peculiar to the OpenID ecosystem, but the same basic problem in both scenarios is possible with even a bog standard username/password system. If you have some disjoint user tables (as Stack Exchange’s are for historical reasons) you can’t just do a correlation between username (or even username & password hash), you need to verify that the same person controls both accounts; and really all you can do is contact both accounts and see if they point to the same person, the mechanism for that being (once again) email.
In a nutshell, if you’ve got more than one kind of credential in your system, say username/password and Facebook Connect, then the only way you’re going to figure out whether the same user has multiple credentials is via correlating email addresses. That Stack Exchange needs this internally is a historical accident, but given the popularity of “Login with Facebook” buttons I have to imagine it comes up elsewhere (perhaps others have consigned themselves to duplicate accounts, or a single external point of failure for user login).
These observations about email are why StackID, Stack Exchange’s own OpenID provider, requires (and confirms) email addresses as part of account creation. We also always share that email address, provided that the relying party asks for it via Simple Registration or Attribute Exchange.

In the English speaking world, names distinct enough for identification outside of a small area really got started with the Domesday Book. Compiled in 1086 CE.
One counter argument I’ve encountered to this position, is that changing your email shouldn’t effectively change your identity. The real life equivalent of changing your email address (changing your street address, phone number, legal name, and so on) is pretty disruptive, why would the internet version be trivial? If nothing else, almost all of your accounts are already relying on your email address for recovery anyway.
I suspect what makes Method of Contact = Email = Identity non-obvious is the tendency of people to assume identity is much simpler that it really is, coupled with the relative youth (and accompanying instability) of the internet. Anecdotally, while I certainly have changed my email address in the past, I’ve been using my current email address for almost as long as I’ve carried a driver’s license (which is good enough ID for most purposes in the United States).
Why I Love Attribute Based Routing
Posted: 2011/07/25 Filed under: code 8 CommentsOver at Stack Exchange we make use of this wonderful little piece of code, the RouteAttribute (an old version can be found in our Data Explorer; a distinct, somewhat hardened, version can also be found as part of StackID, and I link the current version toward the bottom of this post). Thought up by Jarrod “The M is for Money” Dixon sometime around April 2009, this is basically the only thing I really miss in a vanilla MVC project.
Here’s what it looks like in action:
public class UsersController : ControllerBase { [Route("users/{id:INT}/{name?}")] public ActionResult Show(int? id, string name, /* and some more */){ // Action implementation goes here // } }
Nothing awe-inspiring, all that says is “any request starting with /users/ followed by a number of 9 or fewer digits (tossing some valid integers out for simplicity’s sake), and optionally by / and any string should be routed to the Show action”.
Compare this to the standard way to do routing in MVC:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { // Other stuff routes.MapRoute( "Default", "{controller}/{action}/{id}", /* defaults go here */ ); } }
This isn’t exactly 1-to-1 as we end up with /users/show/123 instead of /users/123/some-guy, but now let’s call them equivalent. There are good reasons for why you’d want the /users/{id}/{name} route, which are discussed below.
Where’s the gain in using the RouteAttribute?
Ctrl-Shift-F (search in files, in Visual Studio) is way up there. With the RouteAttribute, the code behind a route is sitting right next to the route registration; trivial to search for. You may prefer to think of it as code locality, all the relevant bits of an Action are right there alongside its implementation.
Some might scoff at the utility of this, but remember that UsersController? That’s split across 14 files. The assumption that enough information to identify the location, in code, of an Action can be shoved in its URL falls apart unless you’re ready to live with really ugly urls.
Action method name flexibility. The RouteAttribute decouples the Action method and Controller names from the route entirely. In the above example, “Show” doesn’t appear anywhere, and the site’s urls are better for it.
Granted, most routes will start out resembling (if not matching) their corresponding method names. But with the RouteAttribute, permalinks remain valid in the face of future method renaming.
You’re also able to be pragmatic with Action method locations in code, while presenting a pristine conceptual interface. An administrative route in, for example, the PostsController to take advantage of existing code would still be reached at “/admin/whatever.”
A minor nicety, with the RouteAttribute it’s easy to map two routes to the same Action. This is a bit ugly with routing rules that include method/controller names, for obvious reasons.
Metadata locality. Our RouteAttribute extends ActionMethodSelectorAttribute, which lets us impose additional checks after route registration. This lets you put acceptable HTTP methods, permitted user types, registration priorities (in MVC, the order routes are registered matters), and the like all right there alongside the url pattern.
A (slightly contrived) example:
[Route("posts/{id:INT}/rollback/{revisionGuid?}", HttpVerbs.Post, EnsureXSRFSafe = true, Priority=RoutePriority.High)]
The strength here is, again, grouping all the pertinent bits of information about a route together. MVC already has enough of this approach, with attributes like HttpPost, that you’ll be decorating Actions with attributes anyway.
No need for [NonAction]. The NonActionAttribute lets you suppress a method on a controller that would otherwise be an Action. I’ll admit, there aren’t a lot of public methods in my code that return ActionResults that aren’t meant to be routable, but there are a number that return strings. Yes, if you weren’t aware, a public method returning a string is a valid Action in MVC.
It seems that back in the before times (in the original MVC beta), you had to mark methods as being Actions rather than not being actions. I think the current behavior (opting out of being an Action) makes sense for smaller projects, but as a project grows you run the risk of accidentally creating routes.
You (probably) want unconventional routing. One argument that has arisen internally against using the RouteAttribute is that it deviates from MVC conventions. While I broadly agree that adhering to conventions is Good Thing™, I believe that the argument doesn’t hold water in this particular case.
The MVC default routing convention of “/{controller}/{action}/{id}” is fine as a demonstration of the routing engine, and for internal or hobby projects it’s perfectly serviceable… but not so much for publicly facing websites.
Here are the two most commonly linked URLs on any Stack Exchange site.
/questions/{id}/{title} as in http://stackoverflow.com/questions/487258/plain-english-explanation-of-big-o
/users/{id}/{name} as in http://stackoverflow.com/users/59711/arec-barrwin
In both cases the last slug ({name} and {title}) are optional, although whenever we generate a link we do our best to include them. Our urls are of this form for the dual purposes of making them user-readable/friendly, and as SEO. SEO can be further divided into hints to Google algorithms (which is basically black magic, I have no confirmation that it actually does anything) and the more practical benefit of presenting the title of a question twice on the search result page.
Closing Statement
Unlike the WMD editor, Booksleeve, or the MVC MiniProfiler we don’t have an open source “drop in and use it” version of the RouteAttribute out there. The versions released incidentally are either out-dated (as in the Data Explorer) or a cut down and a tad paranoid (as in StackID). To rectify this slightly, I’ve thrown a trivial demonstration of our current RouteAttribute up on Google Code. It’s still not a simple drop in (in particular XSRF token checking had to be commented out, as it’s very tightly coupled to our notion of a user), but I think it adequately demonstrates the idea. There are definitely some quirks in the code, but in practice it works quite well.
While I’m real bullish on the RouteAttribute I’m not trying to say that MVC routing is horribly flawed, nor that anyone using it has made a grave error. If it’s working for you, great! If not, you should give attribute based routing a gander. If you’re starting something new I’d strongly recommend playing with it, you just might like. It’d be nice if a more general version of this were shipping as part of MVC in the not-horribly-distant future.
Mobile Views in ASP.NET MVC3
Posted: 2011/07/17 Filed under: code 5 CommentsOn Stack Exchange, we’ve just rolled out a brand spanking new mobile site. This took about 6 weeks of my and our designer’s (Jin Yang) time, the majority of it spent building mobile Views.
Very little time was spent hammering mobile View switching support into MVC, because it’s really not that hard.
A nice thing about the Stack Exchange code base is that all of our Controllers share a common base class. As a consequence, it’s easy to overload the various View(…) methods to do some mobile magic. If your MVC site doesn’t follow this pattern it’s not hard to slap it onto an existing code base, it is a pre-requisite for this approach though.
Here’s the gist of the additions to the Controller base class:
protected new internal ViewResult View() { if (!IsMobile()) return base.View(); var viewName = ControllerContext.RouteData.GetRequiredString("action"); CheckForMobileEquivalentView(ref viewName, ControllerContext); return base.View(viewName, (object)null); } protected new internal ViewResult View(object model) { if (!IsMobile()) return base.View(model); var viewName = ControllerContext.RouteData.GetRequiredString("action"); CheckForMobileEquivalentView(ref viewName, ControllerContext); return base.View(viewName, model); } protected new internal ViewResult View(string viewName) { if (!IsMobile()) return base.View(viewName); CheckForMobileEquivalentView(ref viewName, ControllerContext); return base.View(viewName); } protected new internal ViewResult View(string viewName, object model) { if (!IsMobile()) return base.View(viewName, model); CheckForMobileEquivalentView(ref viewName, ControllerContext); return base.View(viewName, model); } // Need this to prevent View(string, object) stealing calls to View(string, string) protected new internal ViewResult View(string viewName, string masterName) { return base.View(viewName, masterName); }
CheckForMobileEquivalentView() looks up the final view to render, in my design the lack of a mobile alternative just falls back to serving the desktop versions; this approach may not be appropriate for all sites, but Stack Exchange sites already worked pretty well on a phone pre-mobile theme.
private static void CheckForMobileEquivalentView(ref string viewName, ControllerContext ctx) { // Can't do anything fancy if we don't know the route we're screwing with var route = (ctx.RouteData.Route as Route); if (route == null) return; var mobileEquivalent = viewName + ".Mobile"; var cacheKey = GetCacheKey(route, viewName); bool cached; // CachedMobileViewLookup is a static ConcurrentDictionary<string, bool> if (!CachedMobileViewLookup.TryGetValue(cacheKey, out cached)) { var found = ViewEngines.Engines.FindView(ctx, mobileEquivalent, null); cached = found.View != null; CachedMobileViewLookup.AddOrUpdate(cacheKey, cached, delegate { return cached; }); } if (cached) { viewName = mobileEquivalent; } return; }
The caching isn’t interesting here (though important for performance), the important part is the convention of adding .Mobile to the end of a View’s name to mark it as “for mobile devices.” Conventions rather than configurations, after all, being a huge selling point of the MVC framework.
And that’s basically it. Anywhere in your Controllers where you call View(“MyView”, myModel) or similar will instead serve a mobile View if one is available (passing the same model for you to work with).
If you’re doing any whole cloth caching (which you probably are, and if not you probably should be) [ed: I seem to have made this phrase up, “whole cloth caching” is caching an entire response] you’ll need to account for the mobile/desktop divide. All we do is slap “-mobile” onto the keys right before they hit the OuputCache.
One cool trick with this approach is that anywhere you render an action (as with @Html.Action() in a razor view) will also get the mobile treatment. Take a look at a Stack Overflow user page to see this sort of behavior in action. Each of those paged subsections (Questions, Answers, and so on) is rendered inline as an action and then ajax’d in via the same action. In fact, since the paging code on the user page merely fetches some HTML and writes it into the page (via jQuery, naturally) we’re able to use exactly the same javascript on the desktop user page and the mobile one.
I’m not advocating the same javascript between desktop and mobile views in all cases, but when you can do it (as you sometimes can when the mobile view really is just the “shrunk down” version of the desktop) it’ll save you a lot of effort, especially in maintenance down the line.
Another neat tidbit (though MVC itself gets most of the credit here), is the complete decoupling of view engines from the issue. If you want Razor on mobile, but are stuck with some crufty old ASPX files on the desktop (as we are in a few places) you’re not forced to convert the old stuff. In theory, you could throw Spark (or any other view engine) into the mix as well; though I have not actually tried doing that.
As an aside, this basic idea seems to be slated for MVC per Phil Haack’s announcement of the MVC4 Roadmap. I’ve taken it as a validation of the basic approach, if not necessarily the implementation.