Scott Hanselman

Plug-In Hybrids: ASP.NET WebForms and ASP.MVC and ASP.NET Dynamic Data Side By Side

October 1, '08 Comments [32] Posted in ASP.NET | ASP.NET Dynamic Data | ASP.NET MVC | Web Services
Sponsored By

I wanted to write this post because there seems to be a lot of confusion about how ASP.NET WebForms, MVC and Dynamic Data all fit together. Folks may have WebForms applications and want to start looking at ASP.NET MVC but aren't sure if they need to start from scratch or not. Folks might look at Dynamic Data but mistakenly assume it's just for scaffolding administrative sites.

When you're in Visual Studio and you hit "File | New Project" you're given a number of choices. This is a starting point, but it easy to assume that this point is a fork in the road and you can mix them up.

File New Project Dialog

You can (and should) feel free to have Hybrid applications. You can have single Web applications that have all of these inside them (if it makes you happy):

  • ASP.NET MVC
  • ASP.NET WebForms
  • ASP.NET Web Services (ASMX)
  • WCF Services
  • ASP.NET Dynamic Data
  • ASP.NET AJAX

Here's an extreme example. I'll pick ASP.NET MVC Application to start with, but it doesn't really matter. If you're confused as to what web.config entries are required, just make one of each kind of project and compare the files with your favorite diff tool (mine is Beyond Compare).

Ok, so first I've got a Hello World ASP.NET MVC application:

Visual Studio Solution with just ONE MVC application

I'll add a quick LINQ to SQL database connection to the AdventureWorksLT database so I have something to query.

Next, I'll throw a quick ASMX Web Service into this ASP.NET MVC application that returns some data. I create it via File | New Item and select Web Service. I make a quick LINQ expression and a smaller class SmallProduct (a LINQ projection) that is returned. I also make it ScriptService, so I could call it via AJAX if I liked.

namespace Overkill
{
public class SmallProduct
{
public string Name { set; get; }
public string Color { set; get; }
public decimal Price { set; get; }
}

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class Products : System.Web.Services.WebService
{
[WebMethod]
public List<SmallProduct> GetProductsByColor(string color)
{
AdventureWorksDataContext d = new AdventureWorksDataContext();
return (from p in d.Products
where p.Color == color
select new SmallProduct
{
Name = p.Name, Color = p.Color, Price = p.ListPrice
}).ToList<SmallProduct>();
}
}
}

What does this have to do with ASP.NET MVC? Nothing. That's the point. This is an ASP.NET 2.0 style ASMX Web Service with an ASP.NET AJAX ScriptService attribute using a .NET 3.x LINQ Query to return the data, all living in an ASP.NET MVC application.

Why doesn't ASP.NET MVC grab the request? Two reasons. First, there's an option on RouteCollection called RouteExistingFiles. It's set to false by default which causes ASP.NET MVC to automatically skip routing when a file exists on disk.

if (!this.RouteExistingFiles)
{
string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
{
return null;
}
}

Because the default Route in Global.asax isn't greedy enough to care even if we were routing all requests:

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 = "" } // Parameter defaults
);

}

However, in my personal experience, File.Exists is a very expensive operation (very is relativeā€¦it's expensive because it hits the disk at all). A best (and example of attention to detail) practice would be to put in an IgnoreRoute call for those pages, directories, and/or HttpHanders. For example:

routes.IgnoreRoute("{myWebForms}.aspx/{*pathInfo}");
routes.IgnoreRoute("{myWebServices}.asmx/{*pathInfo}");
routes.IgnoreRoute("myCustomHttpHandler.foo/{*pathInfo}");
routes.IgnoreRoute("Contents/{*pathInfo}");

Here I'm ignoring .aspx, .asmx, a custom HttpHandler with a custom extension and the whole of the Contents folder. I might even want to set routes.RouteExistingFiles = true which would turn off the File.Exists check and put ALL the pressure for routing on my routes. I'll need to be more careful and explicit, but that's rarely a bad thing. You could also just structure your site such that all your non-MVC things live in their own folder. It's up to you.

Now, let me add a WebForm and *gasp* drag a GridView into it. Wow, I'm a bad person, I've just used the Designer. I was productive so, but what price my immortal soul? ;)

WebForm with a GridView

Seriously, though, use what makes you happy. This grid is kind of lame, so I'll add some ASP.NET DynamicData. However, while you usually see Dynamic Data from a File | New Application point of view, I'm going to just bring a DynamicDataManager control onto the page. You'll also want to confirm that you have DynamicData controls listed in your web.config:

<pages>
<controls>
<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add tagPrefix="asp" namespace="System.Web.DynamicData" assembly="System.Web.DynamicData, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</controls>
</pages>

I'll add a few things to my WebForms page:

<div>
<asp:DynamicDataManager ID="DynamicDataManager1" runat="server" />
<asp:GridView ID="GridView1" runat="server" DataSourceID="GridDataSource"
AutoGenerateColumns="false" DataKeyNames="ProductID" AllowPaging="true" AllowSorting="true">
<Columns>
<asp:DynamicField DataField="Name" />
<asp:DynamicField DataField="ProductNumber" />
<asp:DynamicField DataField="Color" />
<asp:DynamicField DataField="ListPrice" />
</Columns>
</asp:GridView>
<asp:LinqDataSource ID="GridDataSource" runat="server" EnableDelete="true"
ContextTypeName="Overkill.AdventureWorksDataContext" TableName="Products"/>
</div>

In the Global.asax.cs, I'll add these two lines to let the DynamicData system know that we're working on this DataContext:

MetaModel model = new MetaModel();
model.RegisterContext(typeof(AdventureWorksDataContext), new ContextConfiguration() { ScaffoldAllTables = false });

Then, the most important part, I'll want to bring in the ~\DynamicData folder, since that's where DynamicData finds all of its templates. For this example, I really only need ~\DynamicData\FieldTemplates as I'm only using the smallest bit of Dynamic Data functionality.

To do this easily and quickly, I usually make a throwaway new DynamicData Web Application in another instance of Visual Studio, making sure to give it the same name (and hence, namespace) as the one I'm working on. Then I just drag that project's DynamicData folder over into my original application, and ensure that all the designer files and code-behinds are included in the project (Show All files, then right click each one, Include in Project). The rumor is that there will be a quick way in the future to bring a fresh DynamicData folder into an existing app.

Now, I'll hit my page again and then I get shiny Dynamic Data goodness.

DynamicData

At this point I've got a WebForm, Dynamic Data, and a totally random unused WebService living inside an ASP.NET MVC application. Of course, now this begs the question "Is this an ASP.NET MVC application."

Oh, you wanted MVC used also? ;) I'll add a quick Products method to the HomeController:

public ActionResult Products(string color)
{
AdventureWorksDataContext d = new AdventureWorksDataContext();
var smallProducts = (from p in d.Products
where p.Color == color
select new SmallProduct
{
Name = p.Name,
Color = p.Color,
Price = p.ListPrice
}).ToList<SmallProduct>();
return View("Products", smallProducts);
}

Then a quick view, making sure it's derived from ViewPage<List<SmallProduct>>:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Products.aspx.cs" Inherits="Overkill.Views.Home.Products" %>
<%@ Import Namespace="Overkill" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>
<ul>
<% foreach (SmallProduct p in ViewData.Model)
{ %>
<li><%=p.Name %> <%=p.Price.ToString("C")%></li>

<% } %>
</ul>
</p>
</asp:Content>

And that works also, visiting /Home/Products, ensuring there's a route that matches. I'll make this Route overly specific:

routes.MapRoute(
"ProductsWithColor",
"Home/Products/{color}",
new { controller = "Home", action = "Products", color = "Red" }
);

And it renders like this:

MVCList

I hope this helps and it's more clear now that it's just "an ASP.NET application."

You can feel free to mix and match. Not everyone can (or should) rewrite an existing ASP.NET application, so it is nice that everyone can use some new features in the same ASP.NET application as their existing functionality.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am 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 ORCS Web
Wednesday, October 01, 2008 11:10:27 PM UTC
If I can make a quick point about the template screen you show at the top of the page and us Visual Studio users see often enough, which is that the interface itself implies that those templates might be mutually exclusive and at the very least, it doesn't HELP you to make a hybrid solution. Yes, I get that templates are just shortcuts to a useful solution, but that screen could do much more to help you understand your options and then every visual studio users could understand this without needing to read this blog entry.

Also, the fact that those template and new file type options don't alphabetize by default drives me crazy.
jarrett
Wednesday, October 01, 2008 11:40:30 PM UTC
Thanks Scott, even though I knew this it is super useful seeing it all put together in one place.

david
Thursday, October 02, 2008 12:06:54 AM UTC
Great post Scott. Thanks for showing the relevant uses of the varying technologies.
Thursday, October 02, 2008 1:58:47 AM UTC
wow. just what i was looking for. With MS releasing multiple products like MVC, Dynamic Data, etc. all simultaneously, it is good to know they can all be used in the same project and that they are not mutually exclusive. Get the best out of everything and mix 'em up! Good stuff man! Good stuff.
Thursday, October 02, 2008 2:10:01 AM UTC
Great post Scott. In terms of real world applications however, this would not go down well from an architectural point of view. But it is nice to know that if tinker with these technologies in your spare time, this result can be achieved.
Thursday, October 02, 2008 9:26:26 AM UTC
Great post, Scott!
Thursday, October 02, 2008 9:49:33 AM UTC
In the product I'm currently working on, we have a WinForm Application Designer, used by 5-10 people for each project, with a "Repository" Service. This service provides both a data interface to the DataBase, and a preview for HTML Forms. We mixed aspx WebForms and asmx WebServices in this asp.net server, it works like a charm, and it's easy to mantain.
Also, if different asp.net technologies have to share some files (temporary files, for example) I find it much cleaner to have them all under one single Web Application.
Thursday, October 02, 2008 10:42:03 AM UTC
Darn!! I was just finishing up a blog post about using asp.net mvc and webforms together. Ah well..nice post. Loved that you showed Dynamic Data in there as well.
Friday, October 03, 2008 1:18:05 AM UTC
If it means Dynamic Data Futures and MVC will be come full (meaning native to the product, not the current manual add-ons) members of the .Net family, I can wait before committing to those technologies. I just hope it happens before .Net 4.0, because waiting for .Net 4.0 is going to be a Loooooooooooong wait.

Yes, you can "bolt them together" yourself (I did it with Dynamic Data Futures + existing Dynamic Data), but it's not easy (nor fun), so hurry up and make MVC and Dynamic Data Futures full participating members of .Net 3.x.
Fred Morrison
Friday, October 03, 2008 2:34:46 AM UTC
Now, let me add a WebForm and *gasp* drag a GridView into it. Wow, I'm a bad person, I've just used the Designer. I was productive so, but what price my immortal soul? ;)


But Scott, you work for Microsoft, haven't you already sold your soul?? ;)
Justin
Friday, October 03, 2008 7:54:47 AM UTC

But Scott, you work for Microsoft, haven't you already sold your soul?? ;)

Yes, but when you the Designer the Devil gets a bonus :p
Friday, October 03, 2008 7:56:29 AM UTC
Should have been: "Yes, but when you use the Designer the Devil gets a bonus :p"
Friday, October 03, 2008 8:32:58 AM UTC
This Great,

Can see an example with PHP, RUBY, ASP.NET WebForms, ASP.NET MVC, Perl, MonoRail all mixed into one application, I am interested doing somethin like this but not know where to start.

Please Scott? Help
Mike
Friday, October 03, 2008 8:54:32 PM UTC
Scott,
Thanks for a great post. This definately shows the power of the new tools found in MS VS2008 SP1 :) I just showed 2 or 3 dev's how DD is an awesome tool out of the box and this takes it even further...
Saturday, October 04, 2008 2:54:13 AM UTC
This feels like taking a look at C:\Windows\win.ini in my Vista Ultimate 64-bit install :)

win.ini
--------------------------------
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
yada yada
Saturday, October 04, 2008 12:36:30 PM UTC
Thanks Scott! I've just spent the last couple of weekends agonizing over how to convert my checkout wizard to MVC along with the rest of my site. Turns out I can just give up and keep using Web Forms which seem to do the job just fine.
Saturday, October 04, 2008 5:49:09 PM UTC
This post is exactly what I was looking for! Thanks!

// Dave
Sunday, October 05, 2008 6:21:53 PM UTC
Thank you very much Scott, It's really nice and clean ;)
Siavash Mortazavi
Monday, October 06, 2008 10:09:19 AM UTC
ASP.NET has gone in unmanaged and unstable state where we have 100s of project coded in ASP.NET 2.0 and when we open them in 2008 nothing opens, upgrading to 3.5 are mere nightmares. And finally so many new technologies just to boost the marketing headlines. But come on guys, its easy for one blogger to just blog about able to mix technologies with writing 100s of lines of code which one geek can understand. Have you even worked on any project involving more then 5 developers? Practically we are spending more monty to train new things to our staff, more money to buy new tools, more money to manage projects and more and more money to sit and search world of forums to find why one thing doesnt work then actually doing simple development.

ASP.NET is headless development and we want things that work not new new technologies every day.
Akash Kava
Tuesday, October 07, 2008 3:50:15 PM UTC
Scott,

Have you seen anything on allowing MVC/Dynamic Date site coexisting with URLRewriting.NET.

Thanks,

Michael
Tuesday, October 07, 2008 4:13:49 PM UTC
Great post!! I need to redirect from asp.net web app that uses membership api(aspnetdb), but it fails to pass user credentials to asp.net mvc. Any suggestions?
kushpaw
Friday, October 10, 2008 2:18:01 AM UTC
Thanks Scott, great post. However i dont understand one simple thing... why are you releasing new technology so often? I agree, its very nice to be able to do things differently, but we are working in a commercial environment and we need to get things done. Otherwise no one will be making money and there will be no jobs. And all this "cool" technologies will be used by geeks only. We have invested a lot of money and energy in training people on web forms, now we have to invest even more to re-traing on MVC? This has to stop, we need to look at what we have and improve it, rather then replace it every 3 years. It doesn't make any sence to me. Maybe I need to start looking in using non Microsoft technologies in our future projects.
David
Friday, October 10, 2008 4:49:19 AM UTC
You do realize that web forms still work don't you ? It is not a replacement.. it is an alternative, or an improvement..
If you don't want to learn any new technology, you shouldn't be working in this field...



Mark
Sunday, October 12, 2008 12:43:52 PM UTC
.ToList<SmallProduct>();

the T is not necessary as the projection (IEnumerable<T>) already knows the T ;)

.ToList();

just works

putting the stuff together this way also shows that the project templates thing is kind of broken... as more features come out, it will inevitably become bloated and continue to give the idea that those features are silos...

How about a reworked template that is more intelligent and extensible by current and future functionality? Something like "New ASP.NET Application" which brings a dialog that "products" can extend to inject maybe a checkbox to add features, or maybe an entire wizard page if there are some settings needed for a feature, etc...

Putting together the pieces by creating throwaway apps is no fun... Although it's true you do it only once per project...
Thursday, October 16, 2008 8:31:50 PM UTC
Hi! I like the dynamic data, but I'm a big fan of NHibernate.
In some previous forums you mentioned that there will be some information how could third party orm developers create custom Data context for this? (actually I'm interested of only Nhibernate version :)
Friday, October 17, 2008 12:37:53 PM UTC
Hi Scott,

How would you go about the other way around? Starting with a non-MVC ASP.NET web application and what needs to be done to have it run MVC components. I have been experimenting and can't seem to find a good way. I think that this scenario is more frequent than what you describe here, considering how many "classic ASP.NET" applications are out there. Can you advise?

Thanks,
Laurent
Monday, October 20, 2008 12:15:28 PM UTC
First ilustration : file new project; Question: how did you get VS to organize the dialog semi alphbetically?
Thanks!
Dan Conway
Sunday, October 26, 2008 4:12:09 PM UTC
It is all very nice that we can use these 3 technologies mixed, but it would be a very neat feature that we can enable them in the properties screen of a web project.
So we can asure that they can only be used when enabled (I know the standard ASP.NET will always be available :-) ), but also that all references, folders and minimal files are configured in the current project.
Sunday, October 26, 2008 5:18:37 PM UTC
If you would like to upgrade an existing project to use MVC then add the necessary webreferences from the beta assemblies folder + extra lines in web.config.
When this is done, the MVC will work but you will not be able to select MVC related items when you try to add them to your project. Therefor close your solution and open the project file of your web application and replace the existing <ProjectTypeGuids> tag with the following: <ProjectTypeGuids>{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

{603c0e0b-db56-11dc-be95-000d561079b0} = MVC Items
{349c5851-65df-11da-9384-00065b846f21} = can anyone tell me??
{fae04ec0-301f-11d3-bf4b-00c04f79efbc} = Default ASP.NET
Wednesday, November 05, 2008 9:11:28 AM UTC
I agree a lot with David, Microsoft should have taken the right decesion from the begining, instead of putting developers in risk or as expriemental lab for the new technologies!.. its 2008, I think its kinda late for MVC?

Mark, its not about learning a new technology.. MVC is not a new technology! Its about which technology was the best to go with, for me I've moved to ASP.net because I trusted Microsoft and liked the standards it follows, but today it seems that standards are getting modified! lets hope Microsoft will do it right this time..
Sha
Tuesday, November 18, 2008 7:58:40 AM UTC
David and Sha-

MVC is not a replacement for web forms. Just think of it as a new tool in the web developer's tool box. Web forms aren't going anywhere.
Tim Hobbs
Wednesday, November 19, 2008 11:28:11 AM UTC
Great post Scott,

But if you already have a large WebForms app using some different url re-writing scheme it will be difficult to add MVC because you would need a busload of routes.IgnoreRoute

So for example in mojoPortal CMS content system pages are served by a WebForm page Defalt.aspx?pageid=x, but we have a lot of friendly urls mapped to that one physical .aspx page with different pageids. So it seems we would need to add an routes.IgnoreRoute for every one of the friendly urls and the more pages we have in the site the more unwieldy that would become.

So maybe is not too bad in projects where most of your pages are real physical webform pages, but trying to introduce MVC as an option in a large existing app with a pre-existing url re-writing scheme seems problematic.

If you have any additional tips for this kind of scenario, would love to hear them.

Best,

Joe Audette
Comments are closed.

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