Scott Hanselman

Git support for Visual Studio - Git, TFS, and VS put into Context

January 30, '13 Comments [76] Posted in Open Source | VS2012
Sponsored By

VS loves GitDogs and cats, living together...mass hysteria. This classic Ghostbusters quote is used by many geek-types (myself included) whenever something crazy or unexplained happens.

Today Brian Harry from Microsoft announced Visual Studio 2012 Update 2 (or VS2012.2) the latest quarterly update. That's interesting, but it's the announcement of Git integration with Visual Studio and TFS that is really significant, in my opinion.

TFS in the Past

For me personally, the term "TFS" has historically meant "big scary corporate centralized source control" while Git has meant "small scrappy lightweight distributed source control." TFS meant connected (ZOMG, I can't code on a plane!) and Git meant occasionally connected (ZOMG, I don't know what rebase means!).

However, I learned that Team Foundation Server (TFS) isn't just source control, it's a whole bug tracking, change management, application lifecycle management (ALM) suite. Source control is one pluggable piece.

On the other hand, Git isn't just source control either. Git has become effectively FTP for code. I use Git to deploy most of my sites as mentioned in this blog post where have a site automatically deploy as I publish to GitHub. Git is also used as an interchange tool to move code between different SCMs, and it's supported everywhere, although Git tooling support on Windows has historically lagged behind.

Things start getting interesting if one could have Git as their source control with Team Foundation on the backend for ALM tools. Now Visual Studio 2012 supports both centralized version control and distributed version control in a cleanly integrated way.

Open Source - Working WITH Git

So Visual Studio is integrating Git. Suspicious? This might sound like the "embrace and extinguish" Microsoft from the 90's. Arguments can always be made, but I'm a coder, so I look at the code.

If you dig into the GitHub repo, you can see at least five Microsoft employees (phkelley, ethomson, jamill, martinwoodward, congyiwu) submitting pull requests to the libgit2 GPLv2 library (GPL'ed with a linking exception), including direct commits from phkelley who has earned that access. They work with all the libgit2 committers including Vicent Marti from GitHub. The team has been doing this for months and months. In fact, if anyone was paying attention to commits and pull requests they would have seen this whole convergence coming down Main Street.

 Libgit2 is a great library with a lot of attractive features (from their site):

  • written in portable and standards compilant C
  • completely multi-platform: Windows, Linux, Mac OS X, xBSD and more
  • compiled natively under all platforms (yes, even MSVC on Windows)
  • re-entrant, with sane error handling
  • designed with a solid and consistent API
  • available as bindings for all major scripting language

You can see below that this new Visual Studio Git support actually ships git2 and libgit2sharp and integrates it via a VSIX (Visual Studio Extension).

git2 and libgit2sharp

Visual Studio and Git

This Git support will require VS2012.2 (currently in preview) so you'll need to install that first, then get the VSIX. You'll be able to update both when VS2012.2 is released, and the Git VSIX will continue to update automatically via the VS Gallery. It's a full source code provider for VS so you can use it to do most anything without leaving VS, or you can hang out at the command line and use it for a visual reminder as to the state of your repository.

One file added, one file modified

You can see what will be included in a commit and what's excluded:

Commits to git, both included and excluded

You can make new branches, check them out, as well as see what branches are published or unpublished.

branching in Git in VS

In this screenshot you can can see Keith and I going back and forth on a Pull Request. Note that I've allowed VS in Git Settings to go to Gravatar and get a picture of Keith.

Git History and Gravatars in VS

Here's a screenshot of me managing a recent merge conflict with the VS diff editor then committing the change and pushing it to GitHub. All the diffing is integrated as you'd expect it to be, and available via a Right-Click.

Diff/Merge Conflict within Visual Studio with Git Support.

What's next?

I'm told that while this Git integration is currently in preview. The team work on a three week sprint cadence so expect to see frequent updates.  The plan is that in a future release Git will come baked in to all editions of Visual Studio - including Express. Perhaps we'll see PoshGit command line integration/support and maybe better support for the Git command line within the NuGet Package Manager Console inside VS.

Git within the NuGet Package Manager Console

Hosted Team Foundatation Services - Git or TF Version Control

You can use VS Git support with all your Git projects by just opening projects. It's just Git. I am pushing branches to CodePlex, to GitHub and other Git repos. I'm also continuing to use my other Git tools interchangeably, as I like.

Some teams I work on use Git, others  use TFS. It depends on the team, the company and the goals. Some teams have servers they run themselves, some use hosted Git services at BitBucket or GitHub. There's also hosted Team Foundation Services.

For teams, you can go up to and sign up for a account and get 5 users for free. You can choose either Git or Team Foundation Version Control (TFVC) as the source provider and use all the Team Foundation agile, scrum or other templates for your ALM tools. I've actually got now for my "team." There's issue tracking, backlogs, scrum templates, a Kanban board, burndown charts and more. You can use the web app or use the Visual Studio integration to manage your bugs and backlog. There's even cloud build servers in preview.

TFS online kanban

I've said this before, but I'll say it again. This kind of open source collaboration stuff is why I went to work for The Man. Playing well with others, competing well while using and promoting open source. I don't think every group at Microsoft "gets" it yet, but it's cool to see the open movement spreading. I'm looking forward to using these Git tools for Visual Studio, as well as GitHub for Windows and PoshGit.

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 twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

FREE: Visual Studio Express 2012 for Windows Desktop

September 13, '12 Comments [32] Posted in Open Source | VS2012
Sponsored By

Visual Studio Express 2012 for Windows DesktopWhen the Visual Studio 2012 free versions were originally announced the first thing I noticed was that they had switched from a language-specific model (C# Express, VB Express, etc) to a target-specific model (Windows 8, Web). However, I was very surprised (and disappointed) that there was no free way to make Console Apps, or Windows Forms apps, or anything for the Windows Desktop. I wasn't the only one who thought this was a problem. Shortly thereafter (with a lot of people pushing) Soma announced there would be a "Windows Desktop" Express version for free. He said:

...we heard from our community that developers want to have for Windows desktop development the same great experience and access to the latest Visual Studio 2012 features at the Express level.

Today, I’m happy to announce that we will add Visual Studio Express 2012 for Windows Desktop to the Visual Studio 2012 family. This will bring to the Visual Studio Express family significant new capabilities that we’ve made available in Visual Studio 2012 for building great desktop applications.

I'm glad folks realized that no-cost desktop software development is important. Open Source projects need free tools like the Express SKUs. Even better that the the Express Desktop SKU gets the new 2012 features as well.

Today Visual Studio has made Visual Studio Express 2012 for Windows Desktop available and you can go download it now free. The best part is that this one SKU supports C++, C#, and Visual Basic together. With this one free version you can make WinForms, WPF, Console or Class Libraries with any or all of Visual Basic, C#, as well as Win32 projects, class libraries, and CLR apps using C++. You can also, of course, combine projects over multiple languages into a single solution. You can target both .NET 4.0 and 4.5.

NOTE: You might wonder, what about a free F#? Why isn't F# included? We've got a free download to add F# support to the free Visual Studio Express 2012 for Web!

Related Links

While Express SKUs don't allow arbitrary add-ins (you need Pro for that) the free SKU does include Unit Testing, Code Analysis, as well as the NuGet package manager. It's a bit of a nice coup for my little group that NuGet is now included in ALL Visual Studio 2012 SKUs, even Express ones. Package management is finally happening in .NET.

In the screenshot below I've added a C++ Console app, a Window Forms C# app and a C# Console to a single solution in VS2012 using Express for Windows Desktop.


Just to illustrate one of the reasons I think a free "Desktop" SKU is so important, I wanted to share a cool open source project I found recently called Topshelf. It's a library for making Windows Services easier to write using .NET. It's up on GitHub under an Apache license. The easiest way to get Topshelf is with NuGet with simply "install-package Topshelf". Topshelf has some impressive documentation as well, especially for an open source project!

Here's a simple Windows Service with a basic heartbeat timer using Topshelf:

public class TownCrier
readonly Timer _timer;
public TownCrier()
_timer = new Timer(1000) {AutoReset = true};
_timer.Elapsed += (sender, eventArgs) => Console.WriteLine("It is {0} an all is well", DateTime.Now);
public void Start() { _timer.Start(); }
public void Stop() { _timer.Stop(); }

public class Program
public static void Main()
HostFactory.Run(x => //1
x.Service<TownCrier>(s => //2
s.ConstructUsing(name=> new TownCrier()); //3
s.WhenStarted(tc => tc.Start()); //4
s.WhenStopped(tc => tc.Stop()); //5
x.RunAsLocalSystem(); //6

x.SetDescription("Sample Topshelf Host"); //7
x.SetDisplayName("Stuff"); //8
x.SetServiceName("stuff"); //9
}); //10

Topshelf even has nice Log4net and NLog integration. Anyway, this is just the kind of powerful, useful, and interesting open source library that could be helped by a free Express SKU for Desktop. I'm not involved directly (yet ;) ) in making decisions this high up, but I (and many, many others) inside and out continue to advocate for balance. In this case I'm very glad that the decision was made to ship this SKU and I hope you all find it useful whether you work in open source or in education.

There's more details over at the Visual Studio blog and the team is watching the comments.

This week's sponsor: Be part of GENERATION APP. Your Idea. Your App. 30 Days. Begin your 30-day journey to create a Windows Store style app and talk 1-on-1 with a Windows 8 app development pro. Get started today.

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 twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

ASP.NET Web Forms DynamicData FieldTemplates for DbGeography Spatial Types (plus Model Binders and Friendly URLs)

September 11, '12 Comments [16] Posted in ASP.NET | ASP.NET MVC | Javascript | Open Source | VS2012
Sponsored By

Did you enjoy my recent post on ASP.NET MVC DisplayTemplate and EditorTemplates for Entity Framework DbGeography Spatial Types and it's associated GIANT URL?

Modeling Binding and EditorTemplates...for ASP.NET Web Forms?

DisplayTemplates and EditorTemplates are a great way in ASP.NET MVC to keep things DRY (Don't Repeat Yourself.) That means I can just write EditorFor() calls like this:

@Html.EditorFor(model => model.Location)   

See how I didn't say "TextBoxFor" or "MapFor"? You say EditorFor and it makes the right choice. If the type is called DbGeography then it will look for a Editor Template at ~/Shared/EditorTemplates/DbGeography.cshtml. It's a nice feature of ASP.NET MVC that folks don't use enough.

Now, remember ASP.NET Dynamic Data? You might think that idea "died" or was "retired" when actually the concepts are built into ASP.NET itself. That means that ASP.NET Web Forms developers can have "Editor Templates" as well. They are called FieldTemplates in ASP.NET Web Forms parlance, and making sure we have feature parity like this is part of the larger move towards One ASP.NET. We'll take the ASP.NET MVC sample using DbGeography and make it work for Web Forms in a very similar way.

<%--  Let's not do this: <asp:TextBox ID="location" runat="server" Text="<%# BindItem.Location %>"></asp:TextBox>--%>
<asp:DynamicControl runat="server" ID="Location" DataField="Location" Mode="Insert" />

When we do a POST, ModelBinders handle the boring work of digging types out of the HTTP POST. These work in not just MVC but also Web Forms and Web API now. Rather that Request["this"] and Request["that"] a model binder can be registered to do the work of populating a type from the Request. Even better, we can populate objects not only from the POST but also anywhere that provides values including Cookies, QueryStrings and more.

Let's walk through this one by one and at the end we'll have a complete sample that has:

  • ASP.NET Web Forms and AS.NET MVC in one application, living together.
  • FriendlyURLs for Web Forms and Routing for MVC
  • 90% Shared Model Binding Code between Web Forms and MVC
    • Spatial types custom DbGeography Model Binder
  • Simple CRUD (Create, Read, Update, Delete) to the same database in both Web Forms and MVC using the same model.

The goal is to continue to move towards a cleaner, more unified platform...One ASP.NET. This is an example. Thanks to Pranav for his help!

Related Links

DbGeography FieldTemplates for ASP.NET Web Forms

Here's a FormView in ASP.NET Web Forms. Notice the ItemType is set, rather than using Eval(). We're also using SelectMethod rather than an ObjectDataSource.

<asp:FormView runat="server" ItemType="TouristAttraction" ID="attractionDetails"
<asp:DynamicControl DataField="name" runat="server" ClientIDMode="Static" /><br />
<asp:DynamicControl DataField="location" runat="server" /><br />
<a id="A1" href='<%# FriendlyUrl.Href("~/WebForms/Edit", Item.TouristAttractionId ) %>'>Edit</a> |
<a id="A1" href='<%# FriendlyUrl.Href("~/WebForms") %>'>Back To List</a>

The FormView doesn't specify what a location or name should look like, but since we know the model...

public class TouristAttraction
public int TouristAttractionId { get; set; }
public string Name { get; set; }
public DbGeography Location { get; set; }
} will dynamically figure out the controls (hence, DynamicControl) and find FieldTemplates in the DynamicData folder:

Dynamic Data Field Templates called DbGeography.ascx

Those templates are simple. Here's the Edit example.

<%@ Control Language="C#" CodeBehind="DbGeography_Edit.ascx.cs" Inherits="MvcApplication2.DynamicData.FieldTemplates.DbGeography_EditField" %>

<asp:TextBox runat="server" ID="location" CssClass="editor-for-dbgeography" />

You might say, hang on, this is just a text box! I thought we weren't using TextBoxes? The point is that we have control in a single place over what a DbGeography - or any type - looks like when it's being edited, or when it's read-only. In this example, I AM using a Textbox BUT I've added a CssClass that I will use to create a Google Map using obtrusive JavaScript thanks to my recent refactoring from Dave Ward. If I wanted I could change this FieldTemplate to be a 3rd party control or whatever custom markup I want.

If you have an object called Foo, then make a Foo.ascx and Foo_Edit.ascx and put them in ~/DynamicData/FieldTemplates and they'll be used by DynamicControl.

Model Binding for ASP.NET Web Forms

I did 13 short videos recently on new features in ASP.NET 4.5 including one on Model Binding for ASP.NET Web Forms. Here's the Model Binding one.

Let me first say that Model Binding between ASP.NET Web Forms, MVC and Web API isn't unified. I want more unification and I am continuing to push the One ASP.NET vision internally and many people share that goal.

In the previous blog post on ASP.NET MVC, Model Binding and DbGeography I already had a good Model Binder that I want to reuse between MVC and Web Forms. I can do it, although the ModelBinderProvider stuff isn't very well unified.

First, here's the unified Model Binder for DbGeography that is used for both MVC and Web Forms. We implement two interfaces and use one implementation. Not ideal, but it works.

public class DbGeographyModelBinder : IMvcModelBinder, IWebFormsModelBinder
public object BindModel(ControllerContext controllerContext, MvcModelBindingContext bindingContext)
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
return BindModelImpl(valueProviderResult != null ? valueProviderResult.AttemptedValue : null);

public bool BindModel(ModelBindingExecutionContext modelBindingExecutionContext, WebFormsModelBindingContext bindingContext)
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
bindingContext.Model = BindModelImpl(valueProviderResult != null ? valueProviderResult.AttemptedValue : null);
return bindingContext.Model != null;

private DbGeography BindModelImpl(string value)
if (value == null)
return (DbGeography)null;
string[] latLongStr = value.Split(',');
// TODO: More error handling here, what if there is more than 2 pieces or less than 2?
// Are we supposed to populate ModelState with errors here if we can't conver the value to a point?
string point = string.Format("POINT ({0} {1})", latLongStr[1], latLongStr[0]);
//4326 format puts LONGITUDE first then LATITUDE
DbGeography result = DbGeography.FromText(point, 4326);
return result;

Part of the "trick" are these namespace aliases:

using IMvcModelBinder = System.Web.Mvc.IModelBinder;
using IWebFormsModelBinder = System.Web.ModelBinding.IModelBinder;

using MvcModelBindingContext = System.Web.Mvc.ModelBindingContext;
using WebFormsModelBindingContext = System.Web.ModelBinding.ModelBindingContext;

I'd love to see unification of the Model Binding stack at some point.

In Web Forms we could register a single model binder for a single type like this:

ModelBinderProviders.Providers.RegisterBinderForType(typeof(DbGeography), new DbGeographyModelBinder());

Or collect a collection of like types into a Provider of Binders and add them like this:

ModelBinderProviders.Providers.Insert(0,new EFModelBinderProviderWebForms());

I only have one Model Binder but here's how I'd register a provider for both Web Forms and MVC and have them use my same binder if I wanted:

public class EFModelBinderProviderMvc : System.Web.Mvc.IModelBinderProvider
public IMvcModelBinder GetBinder(Type modelType)
if (modelType == typeof(DbGeography))
return new DbGeographyModelBinder();
return null;

public class EFModelBinderProviderWebForms : System.Web.ModelBinding.ModelBinderProvider
public override IWebFormsModelBinder GetBinder(ModelBindingExecutionContext modelBindingExecutionContext, WebFormsModelBindingContext bindingContext)
if (bindingContext.ModelType == typeof(DbGeography))
return new DbGeographyModelBinder();
return null;

Now, to finish the CRUD.


The team released an alpha build of ASP.NET FriendlyUrls that includes cleaner URLs, easier Routing, and Mobile Views for ASP.NET Web Forms yesterday. I wanted to use them in this project as well, and have WebForms and MVC together in the same app.

I could certainly register a bunch of Web Forms routes manually like this:

RouteTable.Routes.MapPageRoute("Attraction", "WF/Attraction", "~/WebForms/Default.aspx");
RouteTable.Routes.MapPageRoute("AttractionNew", "WF/Attraction/Create", "~/WebForms/Create.aspx");
RouteTable.Routes.MapPageRoute("AttractionEdit", "WF/Attraction/Edit/{id}", "~/WebForms/Edit.aspx");
...and more...

Or I could enable FriendlyUrls after my MVC routes like this:

//MVC will be for MVC, while WebForms is under /WebForms/ using Friendly URLs
name: "Default",
url: "MVC/{controller}/{action}/{id}",
defaults: new { controller = "Attraction", action = "Index", id = UrlParameter.Optional }


Here's what my site looks like now. Notice the /MVC and /WebForms URLs. I can call /WebForms/Create or /MVC/Create..

MVC and Web Forms together in one app

I generate the FriendlyUrls like this in Web Forms:

<a href='<%# FriendlyUrl.Href("~/WebForms/Edit", Item.TouristAttractionId ) %>'>Edit</a>
| <a href='<%# FriendlyUrl.Href("~/WebForms/Delete", Item.TouristAttractionId ) %>'>Delete</a>
| <a href='<%# FriendlyUrl.Href("~/WebForms/Details", Item.TouristAttractionId ) %>'>Details</a>

and like this in MVC

@Html.RouteLink("Edit", "Default",new {Controller="Attraction", action="Edit",id=item.TouristAttractionId}) |
@Html.RouteLink("Details", "Default",new {Controller="Attraction", action="Details",id=item.TouristAttractionId})|
@Html.RouteLink("Delete", "Default",new {Controller="Attraction", action="Delete",id=item.TouristAttractionId})

If this was a larger app I would write better helper methods for both, perhaps using an open source helper library.

UPDATE: One thing I forgot to mention was how to get the values out of the FriendlyURL. You can use things like [Form] and [QueryString] to model bind in WebForms. Now you can add [FriendlyUrlSegments] to get data out, like the ID in this example:

public TouristAttraction attractionsForm_GetItem([FriendlyUrlSegments]int? id)
TouristAttraction touristattraction = db.TouristAttractions.Find(id);
return touristattraction;

Both sections talk to the same database and use the same shared Google Maps JavaScript.

MVC and Web Forms together in one app

I chose not to try to share the _Layout.cshtml and Site.Master, although I could share Razor views and Web Forms.

I've updated the my playground repository with a single project that contains all this. Hope it helps.

Related Links

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 twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Introducing ASP.NET FriendlyUrls - cleaner URLs, easier Routing, and Mobile Views for ASP.NET Web Forms

September 9, '12 Comments [91] Posted in ASP.NET | Javascript | Mobile | Open Source | VS2012
Sponsored By

I've said before how surprised I am that more ASP.NET Web Forms developers don't use Routing to make their URLs prettier. If you don't want "foo.aspx" in your URL, then change it with Routes.MapPageRoute(). However, managing Routing Tables is a little tedious and most WebForms folks aren't used to the concept and don't want to invest the time.

I've also heard a number of ASP.NET Web Forms Developers express a little envy at how easy it is to make a site that has both desktop and mobile views using ASP.NET MVC. They like the idea of seeing an iPhone show up and showing a different  view while reusing logic as I've shown in my mobile talks before.

Let's solve both these problems with a new ASP.NET feature just pre-released today in alpha form on NuGet. My peer Damian Edwards and developer Levi Broderick along with QA by  Pranav and Anton have come up with a pretty awesome solution based on the original "Smarty Routes" idea from Eilon Lipton and the result is FriendlyUrls.

Install-Package Microsoft.AspNet.FriendlyUrls -pre

NOTE: If you've been paying attention to ASP.NET for the last few months you'll recognize this incremental useful but appropriately sized forward motion as being all part of the One ASP.NET master plan.

It's also worth noting that this FriendlyUrls NuGet package includes BOTH an ASP.NET 4.5 and ASP.NET 4 version so .NET 4 folks get love too.

FriendlyUrls Hello World Example

First, the obvious example. Bring up Visual Studio and File | New Project | New ASP.NET Web Forms Application. Now, from the Package Manager Console or from Manage NuGet Packages, install Microsoft.AspNet.FriendlyUrls. You'll need to "Include Prerelease" packages with -pre from the command line or via the dropdown in the UI.

Microsoft.AspNet.FriendlyUrls -pre shown in the UI

Be sure to read the readme.txt that pops up as you'll need to ensure that the FriendlyUrls routing gets called on application startup! I added this one line to my Application_Start:


Here's the cool part. If I hit one of my existing links, like Contact.aspx, look what happened. See how the GET request for /Contact.aspx turned into a 301 redirect to /Contact?

/Contact.aspx turned into a 301 redirect to /Contact

If you have a Web Form called /Foo.aspx, you automatically get a /Foo route and can call your page like that! Hence, Microsoft.AspNet.FriendlyUrls.

Just by adding the one package and calling


in RouteConfig (this default came down with the NuGet package) my whole WebForms app loses its .ASPX extensions and gets reasonable defaults.

FriendlyUrls Advanced Sample

Get it? Ok, let's dig into some of the obvious next questions and some more advanced scenarios. How do I get values out of the URL? I'm used to Request.QueryString and Request.Form, but how do I get ahold of these URL segments?

Here's a Foo.aspx that I've visited via /Foo.

A basic Foo WebForms page

If I click "Click Me" the URL points to /Foo/bar/34.

Visiting /Foo/bar/34

NOTE: Be aware of the magic. It makes sense. If there was a 34.aspx in a folder called Bar in a folder called Foo, we would have used that file. There wasn't. If there was a file called Bar.aspx in a folder called Foo we would have used that. There wasn't. So, we used Foo.aspx and passed in the rest of the URL.

I can get the segments out like this:

<% foreach (var segment in Request.GetFriendlyUrlSegments()) { %>
<li><%: segment %></li>
<% } %>

UPDATE: One thing I forgot to mention was how to get the values out of the FriendlyURL. You can use things like [Form] and [QueryString] to model bind in WebForms. Now you can add [FriendlyUrlSegments] to get data out, like the ID in this example:

public SomeItem SomeItem_GetItem([FriendlyUrlSegments]int? id)
SomeItem item = db.SomeItem.Find(id);
return item;

They're sitting on the Request option. I did have to import the Microsoft.AspNet.FriendlyUrls namespace to have this extension appear.

<%@ Import Namespace="Microsoft.AspNet.FriendlyUrls" %>

Better yet, I can generate Friendly URLs without string concatenation!

<a href="<%: FriendlyUrl.Href("~/Foo", "bar", 34) %>">Click me</a>

Nice, eh? OK, let's make it mobile.

Mobile Routes with ASP.NET FriendlyUrls

When you bring down the NuGet package you'll also get a Site.Mobile.Master. If I visit them with the Electric Plum Mobile Simulator (iPhone) I see a default mobile page, automatically.

The Default Mobile Web Forms page in an iPhone

Ah, you see where this is going. I'll copy Foo.aspx to Foo.Mobile.aspx. I'll make a small change. I'll visit /Foo/bar/34 again except now I get the mobile master and the mobile foo, automatically.


What I want to support switching back and forth from Desktop to Mobile? Just add a ViewSwitcher control, also included.

<friendlyUrls:ViewSwitcher runat="server" />

Now I re-render and I get a "switch to mobile" and switch to desktop.


Now I can go back and forth between views and request a desktop site even when on mobile.


So basic mobile is nice but I might want very specific mobile views for iPhone, iPad, Opera Mobile, etc.

Super Advanced Mobile Routes for Specific Devices with ASP.NET FriendlyUrls

By default FriendlyUrls uses a class called WebFormsFriendlyUrlResolver but you can derive from this class and change its behavior however you like. Here's an example of a "DeviceSpecificWebFormsFriendlyUrlResolver" or, better yet, Mobile Friendly Urls for WebForms.

This derived URL resolver does just that, it resolves URLs to physical Web Forms pages. You'd then pass it into the overload of EnableFriendlyUrls(...);

IMPORTANT NOTE: This code is just a very early sample, there will be a more complete one released later.

public class DeviceSpecificWebFormsFriendlyUrlResolver : WebFormsFriendlyUrlResolver
private readonly IDictionary<string, string> _deviceUserAgentMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{ "Opera Mobi", "OperaMobile" },
{ "iPhone", "iPhone" },
{ "iPad", "iPad" }

protected override IList<string> GetExtensions(HttpContextBase httpContext)
var extensions = base.GetExtensions(httpContext).ToList();
if (extensions.Contains(MobileAspxExtension, StringComparer.OrdinalIgnoreCase))
// Base has determined we should look for a mobile page, let's add device specific
// extension to the beginning.
var deviceSpecificSufffix = GetDeviceSpecificSuffix(httpContext);
if (!String.IsNullOrEmpty(deviceSpecificSufffix))
extensions.Insert(0, "." + deviceSpecificSufffix + AspxExtension);
return extensions;

protected override bool IsMobileExtension(HttpContextBase httpContext, string extension)
return base.IsMobileExtension(httpContext, extension) ||
_deviceUserAgentMap.Values.Any(v => extension.Contains(v, StringComparison.OrdinalIgnoreCase));

protected override bool TrySetMobileMasterPage(HttpContextBase httpContext, Page page, string mobileSuffix)
var deviceSpecificSufffix = GetDeviceSpecificSuffix(httpContext);
if (!String.IsNullOrEmpty(deviceSpecificSufffix) && base.TrySetMobileMasterPage(httpContext, page, deviceSpecificSufffix))
// We were able to set a device specific master page, so just return
return true;

// Just use the base logic
return base.TrySetMobileMasterPage(httpContext, page, mobileSuffix);

private string GetDeviceSpecificSuffix(HttpContextBase httpContext)
foreach (var item in _deviceUserAgentMap)
if (httpContext.Request.UserAgent.Contains(item.Key, StringComparison.OrdinalIgnoreCase))
return item.Value;

return String.Empty;

Now we've created a map of device specific suffixes, so we can have not Foo.Mobile.aspx, but rather Foo.iPhone.aspx and Foo.OperaMobile.aspx, etc.

Here's a little demo that loads a bunch of names into a list. Here's /async, the desktop view.

A list of names on the desktop

Now we'll add jQuery mobile to the mobile master page, and use it on the mobile version of the same page. We're still calling the same data source and reusing all that code.

The list of names now as a jQuery mobile page inside an iPhone

I'm pretty jazzed about what this means for ASP.NET and Web Forms developers. We're going to continue to push forward and improve ASP.NET even now, after Visual Studio 2012 has been released. Sometimes we'll add small features via NuGet packages, sometimes editor improvements as free VSIX Extensions like the Web Essentials playground for 2012 and larger changes via released updates to all of ASP.NET.  I hope you like the direction we're heading.

Go play with Microsoft.AspNet.FriendlyUrls now and thank Damian and friends on Twitter!

This week's sponsor: Be part of GENERATION APP. Your Idea. Your App. 30 Days. Begin your 30-day journey to create a Windows Store style app and talk 1-on-1 with a Windows 8 app development pro. Get started today.

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 twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Your Colorful Visual Studio 2012 with the Color Theme Editor (VS2010 colors, too)

September 7, '12 Comments [59] Posted in Tools | VS2012
Sponsored By

The stock Visual Studio 2012 gray color scheme is growing on me. Sue me. When you're writing code you usually focus on the code so I'm more concerned with the colors of the code than the chrome.

Here's my default, which is the VS2012 defaults with larger fonts.

VS2012 with the default color scheme

Here is Visual Studio 2012 again, except this time I've used Matthew Johnson's Visual Studio 2012 Color Theme Editor and applied the Blue theme:

VS2012 with VS2010 colors

Here it is again with the ALL CAPS registry setting turned off:

REG_DWORD value: 1

Now you're pretty much back to the VS2010 look and feel. I've zoomed in here to make it clear.

Visual Studio 2012 with the ALL CAPS menu removed and the VS2010 colors restored

Go nuts! You can make and share custom themes yourself! With this add-in you can customize a lot more than the default installation allows:

A wide range of color options

Have fun! Go get Matthew Johnson's Visual Studio 2012 Color Theme Editor now.

UPDATE: I personally would not go this far, but you can also patch the icons if you feel strongly about it.

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 twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Previous Page Page 2 of 3 in the VS2012 category Next Page

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