Scott Hanselman

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

October 02, 2008 Comment on this post [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. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
October 02, 2008 3:10
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.
October 02, 2008 3:40
Thanks Scott, even though I knew this it is super useful seeing it all put together in one place.

david
October 02, 2008 4:06
Great post Scott. Thanks for showing the relevant uses of the varying technologies.
October 02, 2008 5:58
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.
October 02, 2008 6:10
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.
October 02, 2008 13:26
Great post, Scott!
October 02, 2008 13:49
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.
October 02, 2008 14:42
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.
October 03, 2008 5:18
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.
October 03, 2008 6:34
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?? ;)
October 03, 2008 11:54

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
October 03, 2008 11:56
Should have been: "Yes, but when you use the Designer the Devil gets a bonus :p"
October 03, 2008 12:32
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
October 04, 2008 0:54
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...
October 04, 2008 6:54
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
October 04, 2008 16:36
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.
October 04, 2008 21:49
This post is exactly what I was looking for! Thanks!

// Dave
October 05, 2008 22:21
Thank you very much Scott, It's really nice and clean ;)
October 06, 2008 14:09
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.
October 07, 2008 19:50
Scott,

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

Thanks,

Michael
October 07, 2008 20:13
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?
October 10, 2008 6:18
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.
October 10, 2008 8:49
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...



October 12, 2008 16:43
.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...
October 17, 2008 0:31
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 :)
October 17, 2008 16:37
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
October 20, 2008 16:15
First ilustration : file new project; Question: how did you get VS to organize the dialog semi alphbetically?
Thanks!
October 26, 2008 20:12
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.
October 26, 2008 21:18
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
November 05, 2008 13:11
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
November 18, 2008 11:58
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.
November 19, 2008 15:28
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
Joe

Comments are closed.

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