Minggu, 23 Januari 2011

Hanselminutes Podcast 247 - From Agile Consultant to Agile Team Member with John Wilger


imageScott sits down with former agile coach John Wilger to talk about his experience going to work for the company he originally consulted with. What kinds of issues do small teams deal with when moving from traditional software development processes?

Download: MP3 Full Show

NOTE: If you want to download our complete archives as a feed - that's all 247 shows, subscribe to the Complete MP3 Feed here.

Also, please do take a moment and review the show on iTunes.

Subscribe: Subscribe to Hanselminutes or Subscribe to my Podcast in iTunes or Zune

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is our sponsor for this show.

Building quality software is never easy. It requires skills and imagination. We cannot promise to improve your skills, but when it comes to User Interface and developer tools, we can provide the building blocks to take your application a step closer to your imagination. Explore the leading UI suites for ASP.NET AJAX,MVC,Silverlight,Windows Forms and WPF. Enjoy developer tools like .NET Reporting, ORM, Automated Testing Tools, Agile Project Management Tools, and Content Management Solution. And now you can increase your productivity with JustCode, Telerik’s new productivity tool for code analysis and refactoring. Visit www.telerik.com.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?



© 2010 Scott Hanselman. All rights reserved.

VS 2010 SP1 (Beta) and IIS Express


Last month we released the VS 2010 Service Pack 1 (SP1) Beta. You can learn more about the VS 2010 SP1 Beta from Jason Zander’s two blog posts about it, and from Scott Hanselman’s blog post that covers some of the new capabilities enabled with it.

You can download and install the VS 2010 SP1 Beta here.

IIS Express

Earlier this summer I blogged about IIS Express. IIS Express is a free version of IIS 7.5 that is optimized for developer scenarios. We think it combines the ease of use of the ASP.NET Web Server (aka Cassini) currently built-into VS today with the full power of IIS. Specifically:

  • It’s lightweight and easy to install (less than 5Mb download and a quick install)
  • It does not require an administrator account to run/debug applications from Visual Studio
  • It enables a full web-server feature set – including SSL, URL Rewrite, and other IIS 7.x modules
  • It supports and enables the same extensibility model and web.config file settings that IIS 7.x support
  • It can be installed side-by-side with the full IIS web server as well as the ASP.NET Development Server (they do not conflict at all)
  • It works on Windows XP and higher operating systems – giving you a full IIS 7.x developer feature-set on all Windows OS platforms

IIS Express (like the ASP.NET Development Server) can be quickly launched to run a site from a directory on disk. It does not require any registration/configuration steps. This makes it really easy to launch and run for development scenarios.

Visual Studio 2010 SP1 adds support for IIS Express – and you can start to take advantage of this starting with last month’s VS 2010 SP1 Beta release.

Downloading and Installing IIS Express

IIS Express isn’t included as part of the VS 2010 SP1 Beta. Instead it is a separate ~4MB download which you can download and install using this link (it uses WebPI to install it).

Once IIS Express is installed, VS 2010 SP1 will enable some additional IIS Express commands and dialog options that allow you to easily use it.

Enabling IIS Express for Existing Projects

Visual Studio today defaults to using the built-in ASP.NET Development Server (aka Cassini) when running ASP.NET Projects:

image

Converting your existing projects to use IIS Express is really easy. You can do this by opening up the project properties dialog of an existing project, and then by clicking the “web” tab within it and selecting the “Use IIS Express” checkbox.

Or even simpler, just right-click on your existing project, and select the “Use IIS Express…” menu command:

image

And now when you run or debug your project you’ll see that IIS Express now starts up and runs automatically as your web-server:

image

You can optionally right-click on the IIS Express icon within your system tray to see/browse all of sites and applications running on it:

image

Note that if you ever want to revert back to using the ASP.NET Development Server you can do this by right-clicking the project again and then select the “Use Visual Studio Development Server” option (or go into the project properties, click the web tab, and uncheck IIS Express). This will revert back to the ASP.NET Development Server the next time you run the project.

IIS Express Properties

Visual Studio 2010 SP1 exposes several new IIS Express configuration options that you couldn’t previously set with the ASP.NET Development Server. Some of these are exposed via the property grid of your project (select the project node in the solution explorer and then change them via the property window):

image

For example, enabling something like SSL support (which is not possible with the ASP.NET Development Server) can now be done simply by changing the “SSL Enabled” property to “True”:

image

Once this is done IIS Express will expose both an HTTP and HTTPS endpoint for the project that we can use:

image

SSL Self Signed Certs

IIS Express ships with a self-signed SSL cert that it installs as part of setup – which removes the need for you to install your own certificate to use SSL during development. Once you change the above drop-down to enable SSL, you’ll be able to browse to your site with the appropriate https:// URL prefix and it will connect via SSL.

One caveat with self-signed certificates, though, is that browsers (like IE) will go out of their way to warn you that they aren’t to be trusted:

image

You can mark the certificate as trusted to avoid seeing dialogs like this – or just keep the certificate un-trusted and press the “continue” button when the browser warns you not to trust your local web server.

Additional IIS Settings

IIS Express uses its own per-user ApplicationHost.config file to configure default server behavior. Because it is per-user, it can be configured by developers who do not have admin credentials – unlike the full IIS. You can customize all IIS features and settings via it if you want ultimate server customization (for example: to use your own certificates for SSL instead of self-signed ones).

We recommend storing all app specific settings for IIS and ASP.NET within the web.config file which is part of your project – since that makes deploying apps easier (since the settings can be copied with the application content). IIS (since IIS 7) no longer uses the metabase, and instead uses the same web.config configuration files that ASP.NET has always supported – which makes xcopy/ftp based deployment much easier.

Making IIS Express your Default Web Server

Above we looked at how we can convert existing sites that use the ASP.NET Developer Web Server to instead use IIS Express.

You can configure Visual Studio to use IIS Express as the default web server for all new projects by clicking the Tools->Options menu command and opening up the Projects and Solutions->Web Projects node with the Options dialog:

image

Clicking the “Use IIS Express for new file-based web site and projects” checkbox will cause Visual Studio to use it for all new web site and projects.

Summary

We think IIS Express makes it even easier to build, run and test web applications. It works with all versions of ASP.NET and supports all ASP.NET application types (including obviously both ASP.NET Web Forms and ASP.NET MVC applications). Because IIS Express is based on the IIS 7.5 codebase, you have a full web-server feature-set that you can use. This means you can build and run your applications just like they’ll work on a real production web-server. In addition to supporting ASP.NET, IIS Express also supports Classic ASP and other file-types and extensions supported by IIS – which also makes it ideal for sites that combine a variety of different technologies.

Best of all – you do not need to change any code to take advantage of it. As you can see above, updating existing Visual Studio web projects to use it is trivial. You can begin to take advantage of IIS Express today using the VS 2010 SP1 Beta.

Hope this helps,

Scott

Adding a Netgear N600 Wireless Dual Band Gigabit Router WNDR3700 to an existing FIOS Wireless AP for improved wireless coverage


A few months ago I added a second wireless access point (AP) to my existing network in order to get better wireless coverage. We have a house that's kind of spread out and we were getting really spotty 802.11g around the house. Laptops we getting one or two bars, or worse yet, they were constantly negotiating network speeds and never getting a decent one. The iOS devices (iPhone, iPad, etc) would barely get any signal in certain rooms. It was certainly irritating.

So, I added a second identical AP with the same SSID upstairs so we could move between floors without trouble. However, this AP (some crappy standard one that came with the FIOS service) was/is really inconsistent. While the network architecture is solid, as is the idea behind my "add a second AP" post, the implementation using these 5 year old crappy routers was flaky at best.

Techie Background: I have FIOS optical internet service, and have for the last 3 years. It's upgraded from 15Mbs to 35Mbs recently. The house is Gigabit Ethernet (all CAT6, see the related links below). All the wired devices are running through a Netgear GS724T-300 24-port Gigabit Smart Switch and all of the wireless devices are at least 2.4Ghz 802.11g, and some are 802.11n, with one being 2.4Ghz or 5Ghz.

Since I have a home office, meaning I literally work at home 90% of the time for my living, having flaky wireless is a problem. I decided to start researching a better solution. I decided to add a new wireless router. I figured that it was insane for one house to have to APs and that surely if a cell phone could work over miles that a freaking wireless network router could cover a single house. I found the solution in the Netgear N600 Gigabit.

Here's the idea:

Network Diagram with additional Wireless Router

However, there are some important notes when adding a new wireless router to an existing system that is already performing these functions

  • Passing out IP addresses via HDCP
  • Acting as a wireless access point with lots of existing clients
  • Has existing static IP leases setup, existing quality of service (QoS) settings

Stated differently, my existing router is nicely and intricately configured for my house. It works fine and I like it fine, except it has crappy wireless. I want to add a new wireless router without disturbing what already works. If it ain't broke, don't fix it.

I picked up a Netgear N600 Wireless Gigabit Router. Note that there are two versions of this, one with a large bright LED on the outside and one without. The one without has 4 Gigabit LAN ports, and that's the better router.

Let me tell you that this router is awesome. I figured I'd be moving from a 3-5 year old crappy router to some better router, sure, but not a totally awesome Swiss Army Knife. Networking has come a long way since 2005 or whenever my stock router was made.

This Netgear is awesome because of these features:

  • Two separate bands for wireless, each with 300Mbs of independent bandwidth. There's 2.4GHz and 5.0GHz frequencies. Nice for copying VMs over wireless. I made a "HANSELMAN" and "HANSELMAN-N" network.
  • Four Gigabit Ethernet points. Not needed for me, but it's nice to have four more Gigabit ports.
  • Eight internal antennas - Seriously, this thing has insane range. I had already added an external antenna to my FIOS router and still had bad range. This little Netgear covers 3500+ square feet and more. I'm thrilled with the range. I don't need two routers anymore. Adding this router totally achieved my goal.

There were a few gotchas. I still need my ISP's router because it's the bridge to the ISP and the Optical Network Terminal (ONT) they installed on the house. It's also totally configured as I like.

Here's the steps I took:

  • Logged into the FIOS ActionTec at http://192.168.1.1 and disabled the wireless interface. I confirmed that the "HANSELMAN" network was no longer showing up.
  • Plugged the Netgear directly into my laptop and visited it's default IP of http://10.0.0.1. I disabled the new router's DHCP (this is crucial).
    • Important Trick: I temporarily plugged the new Netgear's yellow "external network" directly into the FIOs ActionTec so the Netgear could update its firmware the first time and get the initial setup wizard would stop nagging me. The router expects to be hooked up in this way at least initially, so you need to satisfy its setup.
  • After the Netgear is configured, now unplug the yellow external LAN wire and instead plug into one of the standard four ethernet ports into either your switch (that's what I did, gigabit to gigabit) or directly into your ISP's router. We want the new router to get an IP address from our existing router and route traffic and DHCP requests to the ISP's router. To be clear: Setting up your new router in this way will leave the yellow upstream external network port empty, despite what the documentation says.
  • On the new router, setup the 2.4GHz wireless network with your SSID, and the 5GHz wireless network with something like YOURSSID-N. Here's what I did:
  • View Available Networks Dialog

Now I've got 192.x.x.x addresses being handed out on two wireless networks. My Wireless-N network is getting 300Mbs throughput on my Lenovo, as its Intel Wireless LAN does 5Ghz 802.11n. Also, my iOS devices are using 2.4Ghz 802.11n and are suddenly a LOT snappier on large downloads and email.

Wireless Network Connection Status

I'm absolutely thrilled with the a Netgear N600 Wireless Gigabit Router. It's the top of the line for the house, definitely a "prosumer" router and a really nice upgrade to any existing system if you know a little about setting up your network. Totally recommended.

Related Links



© 2010 Scott Hanselman. All rights reserved.

The Weekly Source Code 58 - Generating (Database) Test Data with AutoPoco and Entity Framework Code First


I was messing around with Entity Framework Code First for data access recently (what I like to call EF Magic Unicorn) and had a need to create a bunch of test data. Such a chore. It's totally no fun and I always end up slapping the keyboard thinking that someone else should be slapping the keyboard. Test data for 10 instances of a class is easy, but 1000 is some how less inspiring.

Sure, there's lots of software I could buy to solve a problem like that, but meh. I dug around some and found an open source framework called AutoPoco from Rob Ashton (@robashton). First, awesome name. I like using open source projects with cool names. It's kind of like reading a book with a great cover. Makes you feel good jumping in. Then, I started working with it and realized there's some substance to this modest little library. All the better, right?

AutoPoco's CodePlex project says:

AutoPoco is a highly configurable framework for the purpose of fluently building readable test data from Plain Old CLR Objects

Here's the general idea. You need 100 of something (or 5, or whatever) setup a certain way, so you ask AutoPoco to construct a bunch of you, and it's so. It's that easy.

For example, please get me 1000 objects of type SimpleUser and make their FirstName's all "Bob.":

IList<SimpleUser> users = session.List<SimpleUser>(1000).Impose(x => x.FirstName, "Bob").Get();


Here's where it really shines, though:



session.List<SimpleUser>(100)
.First(50)
.Impose(x => x.FirstName, "Rob")
.Impose(x => x.LastName, "Ashton")
.Next(50)
.Impose(x => x.FirstName, "Luke")
.Impose(x => x.LastName, "Smith")
.All().Random(25)
.Impose(x => x.Role,roleOne)
.Next(25)
.Impose(x => x.Role,roleTwo)
.Next(50)
.Impose(x => x.Role, roleThree)
.All()
.Invoke(x => x.SetPassword("Password1"))
.Get();


This says:




Create 100 users

The first 50 of those users will be called Rob Ashton


The last 50 of those users will be called Luke Smith


25 Random users will have RoleOne


A different 25 random users will have RoleTwo


And the other 50 users will have RoleThree


And set the password on every single user to Password1




Effectively, the sky's the limit. You can also give AutoPoco more advanced requirements like 'make emails meet these requirements," or "call this method when it's time to get a password." The idea being not just to make test data, but to make somewhat meaningful test data.



This got me thinking that since we're using POCOs (Plain Ol' CLR Objects) that I could use this not only for Unit Tests but also Integration Tests and Smoke Tests. I could use this to generate test data in a database. All the better to use this with the new Entity Framework stuff that also uses POCOs.



For example:



public void MakeTestData()
{
IGenerationSessionFactory factory = AutoPocoContainer.Configure(x =>
{
x.Conventions(c => { c.UseDefaultConventions(); });
x.AddFromAssemblyContainingType<SimpleUser>();
});

IGenerationSession session = factory.CreateSession();

IList<SimpleUser> users = session.List<SimpleUser>(1000)
.First(500)
.Impose(x => x.FirstName, "Bob")
.Next(500)
.Impose(x => x.FirstName, "Alice")
.All()
.Impose(x => x.LastName, "Hanselman")
.Random(250)
.Impose(x => x.LastName, "Blue")
.All().Random(400)
.Impose(x => x.LastName, "Red")
.All()
.Get();

SimpleUserDatabase db = new SimpleUserDatabase();
foreach (SimpleUser s in users)
{
db.Users.Add(s);
}
db.SaveChanges();
}


And boom, I've got 1000 users in my little database.



I've talked to the author, Rob, and I think that the Session creation and Factory stuff could be made smaller, and the loop at the bottom could be reduced a line or two. Rob's a practical guy, and I look forward to where AutoPoco goes next! All in all, what a useful library. I can see myself using this a lot.



You can get AutoPoco from CodePlex, or even better, from inside Visual Studio using NuGet (http://nuget.org) via "install-package autopoco."



Enjoy! This library has 36 downloads, but deserves a few orders of magnitudes more. I'll do my best to showcase more open source libraries that deserve attention (and more importantly, to be used!) going forward. Feel free to email me suggestions of insanely useful libraries.



© 2010 Scott Hanselman. All rights reserved.

Integrating ASP.NET MVC 3 into existing upgraded ASP.NET 4 Web Forms applications


I got an interesting question recently from a gentleman who has an existing ASP.NET WebForms 2.0 application that works just fine. He's upgraded it to ASP.NET 4 and it still works great, but now he wants to add some ASP.NET MVC pages to it. He doesn't want to rewrite the application.

A few years ago I did a post on "Hybrid" ASP.NET applications. The goal was to reinforce the point that you can have ASP.NET applications that are both WebForms and MVC (as well as WCF and ASMX Web Services and on and on.) While the File|New Project dialog gives you a choice between This and That, in fact it's all ASP.NET underneath. You are welcome to mix and match "cafeteria style" and create apps in any combination you'd like.

The easiest way to add ASP.NET MVC 3 to an upgraded ASP.NET 2.0 WebForms application:

  • Run the Upgrade Wizard (open the Visual Studio2008 Web Application in Visual Studio 2010)
  • Create a default ASP.NET MVC application for reference (you'll throw it away later)
  • Use a differencing tool like Beyond Compare to integrate the new web.config entries from the ASP.NET MVC sections into the upgraded ASP.NET WebForms application
  • Dance

Here's the longer more detailed version of the above.

Upgrading an ASP.NET 2.0 WebForms Application

I've created a simple Visual Studio 2008 ASP.NET WebForms Application running under .NET 2. It's a simple calculator.

WebApplication1 - Microsoft Visual Studio (7)

It works nicely. Now, open this application in Visual Studio 2010. You'll get the Conversion/Upgrade Wizard.

Visual Studio Conversion Wizard (6)

Next, Next, Yada, Yada, Yada, Finish. You'll get an prompt to upgrade the 2.0 application to .NET Framework 4. Click Yes.

Web Site targeting older .Net Framework Found (8)

Here's the same WebForms application, now upgraded in Visual Studio 2010. It still runs and it's still WebForms. Or, more accurately, it continues to be ASP.NET.

WebApplication1 - Microsoft Visual Studio (9)

I'm going to take a new default ASP.NET MVC 3 application and Beyond Compare and compare the upgraded app with the default app.

WebApplication1 _--_ MvcApplication1 - Folder Compare - Beyond Compare (10)

I'll copy over these folders and files:

  • Content
  • Controllers
  • Models
  • Scripts
  • Views
  • Global.asax, Global.asax.cs

Now, here's the before and after references from the upgraded application. The old on the left and the new on the right.

New ReferencesReferences

Here's the references I added.

  • Microsoft.CSharp
    • (as this was a C# app)
  • System.Web.Mvc
    • From \Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 3\Assemblies
  • System.Web.WebPages and System.Web.Razor
    • From \Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies
  • System.ComponentModel.DataAnnotations

Next, add these sections to the Web.config. Again, it's easier to use a diff tool and you might have a little trial and error.

Thought: This might be a nice NuGet package for someone to make...

Add these settings in appSettings:

<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>


Add these assembly elements under compilation:



<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>


Add these namespaces in pages:



<system.web>
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages"/>
</namespaces>
</pages>
</system.web>


If you're running IIS7 at some point, which I'm sure you will, add these:



<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>


And finally add this assembly binding redirect, just in case you've got ASP.NET MVC 1 or 2 assemblies in your Global Assembly Cache (GAC).



<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>


Also, make sure you merge in the Global.asax.cs so that your Routes are registered at application startup.



public class SomeHybrid: System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}


Now, at this point I can visit both pages. The WebForms page is a file on disk, so ASP.NET routing passes requests directly on to this page when I /default.aspx. The ASP.NET Routing engine is engaged so I can also hit /Home/Index.



If I want to get fancy, I can add a PageRoute so I have pretty URLs when visit my WebForms pages as well. Just add a route in the Global.asax like this. Make sure that simple routes like these come first, as the default ASP.NET MVC route is very "greedy" and would gobble up a simple URL like /calculator



routes.MapPageRoute("WebFormThing", "Calculator", "~/Default.aspx");


Now I can visit /Calculator and the request is routed to /Default.aspx. And of course, my ASP.NET MVC 3 Razor pages like /Home/Index work also.



http___localhost_12089_Calculator - Windows Internet Explorer (18)



Finally, just to make the point, here's the Default.aspx from the WebForms part of my new app next to the source for a Razor page.



WebApplication1 - Microsoft Visual Studio (16)



You CAN have it all, Dear Reader. Enjoy.



© 2010 Scott Hanselman. All rights reserved.

Razor Syntax Quick Reference


I gave a presentation to another team at Microsoft yesterday on ASP.NET MVC and the Razor view engine and someone asked if there was a reference for the Razor syntax.

It turns out, there is a pretty good guide about Razor available, but it’s focused on covering the basics of web programming using Razor and inline pages and not just the Razor syntax.

So I thought it might be handy to write up a a really concise quick reference about the Razor syntax.




















































































Syntax/Sample Razor Web Forms Equivalent (or remarks)
Code Block
@{
int x = 123;
string y = 'because.';
}


<%
int x = 123;
string y = 'because.';
%>

Expression (Html Encoded)
<span>@model.Message</span>


<span><%: model.Message %></span>

Expression (Unencoded)
<span>
@Html.Raw(model.Message)
</span>


<span><%= model.Message %></span>

Combining Text and markup
@foreach(var item in items) {
<span>@item.Prop</span>
}


<% foreach(var item in items) { %>
<span><%: item.Prop %></span>
<% } %>

Mixing code and Plain text
@if (foo) {
<text>Plain Text</text>
}


<% if (foo) { %>
Plain Text
<% } %>

Mixing code and plain text (alternate)
@if (foo) {
@:Plain Text is @bar
}

Same as above
Email Addresses
Hi philha@example.com

Razor recognizes basic email format and is smart enough not to treat the @ as a code delimiter
Explicit Expression
<span>ISBN@(isbnNumber)</span>

In this case, we need to be explicit about the expression by using parentheses.
Escaping the @ sign
<span>In Razor, you use the
@@foo to display the value
of foo</span>

@@ renders a single @ in the response.
Server side Comment
@*
This is a server side
multiline comment

*@


<%--
This is a server side
multiline comment
--
%>

Mixing expressions and text
Hello @title. @name.


Hello <%: title %>. <%: name %>.



Notice in the last example that Razor is smart enough to know that the ending period is a literal text punctuation and not meant to indicate that it’s trying to call a method or property of the expression.



Let me know if there are other examples you think should be placed in this guide. I hope you find this helpful.



Grouping Routes Part 2


In part 1 of this series, we looked at the scenario for grouping routes and how we can implement matching incoming requests with a grouped set of routes.

In this blog post, I’ll flesh out the implementation of URL Generation.

Url Generation Implementation

URL generation for a group route is tricky, especially when using named routes because the individual routes that make up the group aren’t in the main route collection.

As I noted before, the only route that’s actually added to the route table is the GroupRoute. Thus if you supply a route name for one of the child routes (such as “r1”) during URL generation, you’ll get a null URL.

Interestingly enough, in this case, if you don’t use named routes when using URL generation, everything works just fine. However, since I heartily recommend using named routes all the time, I should cover that situation.

So what we need to do here is supply two route names during URL generation. One for the group route, and one for the child route. How do we supply the child route name? We’re going to have to supply it in the route values. Here’s an example of generating an URL in this manner:

@Html.RouteLink('Hello World Child', 'group',
new { __RouteName = 'hello-world3' })




Note that the second parameter, “group”, refers to the route name for the GroupRoute that we registered. The route value __RouteName is passed into the GroupRoute so that it can look in its own collection of routes for the matching child route.



In the following code sample, I’ve highlighted the essential part of the URL generation logic within the GroupRoute class.





public override VirtualPathData GetVirtualPath(RequestContext
requestContext, RouteValueDictionary values) {
string routeName = values.GetRouteName();
var virtualPath = ChildRoutes.GetVirtualPath(requestContext,
routeName as string, values.WithoutRouteName());
if (virtualPath != null) {
string rewrittenVirtualPath =
virtualPath.VirtualPath.WithoutApplicationPath(requestContext);
string directoryPath = VirtualPath.WithoutTildePrefix(); // remove tilde
rewrittenVirtualPath = rewrittenVirtualPath.Insert(0,
directoryPath.WithoutTrailingSlash());
virtualPath.VirtualPath = rewrittenVirtualPath.Remove(0, 1);
}

return virtualPath;
}




The code grabs the route name for the child route from the supplied route values. Notice that I’m using an extension method I wrote in my last blog post.



The block of code after the highlighted portion rewrites the virtual path back to the full virtual path for the parent GroupRoute. This ensures that the virtual path that’s eventually returned to the caller will actually work, since the individual routes within the group don’t have a clue that they’re within a group.



In a follow-up blog post, I’ll wrap up this series and provide access to the full source code.