Scott Hanselman

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

January 06, 2011 Comment on this post [42] Posted in ASP.NET | ASP.NET MVC | VS2010
Sponsored By

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.

About Scott

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

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

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

January 05, 2011 Comment on this post [26] Posted in Open Source | Source Code
Sponsored By

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.

About Scott

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

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

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

January 04, 2011 Comment on this post [28] Posted in Hardware | Tools
Sponsored By

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

About Scott

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

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

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

January 03, 2011 Comment on this post [4] Posted in Agile | Podcast
Sponsored By

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?

About Scott

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

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

Hanselminutes Podcast 246 - Hanselminutiae-nine with Richard Campbell

January 03, 2011 Comment on this post [0] Posted in Podcast
Sponsored By

Happy holidays! It's a totally random chat show with Richard Campbell. What's next for Windows Phone 7? Will Scott give up his iPhone? How many Kindles can one man own? Is Kinect the future of computing? All this and less on this episode.

Download: MP3 Full Show

NOTE: If you want to download our complete archives as a feed - that's all 246 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?

About Scott

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

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

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