Microsoft just released version 1.0 of Web Application Projects, which is a much-needed add-in for Visual Studio 2005. This add-in project type addresses a number of issues related to page compilation, project creation, and management as well as deployment in ASP.NET 2.0 and Visual Studio 2005 by providing a project model that more closely resembles VS2003 projects. If you’ve had any kind of issues with project management, compilation or deployment, you should definitely check out this new add-in that brings back an old but proven concept.
Web Application Projects come in response to some fairly noisy criticism of the stock project model that Microsoft shipped with Visual Studio 2005. Many developers in the community ran into quirky behavior due to the complex new compilation model. Ironically, the new stock compilation model was supposed to make it easy to create and work with Web applications, and while it does make many things easier most of the time, the few things it doesn’t do well can be major stumbling blocks.
Deployment is also affected by the compilation and project model and many developers ended up downright baffled by the messy deployment output generated by stock projects. The output contains a ton of randomly named files and projects cannot create a repeatable installation unless doing an in-place install including source files.
In addition, there are project management issues because stock projects aren’t real Visual Studio projects and some features that have always been available to projects like Build Actions, XML documentation, and MS Build support, are simply not available.
Microsoft Responds Quickly
Microsoft took the issues raised quite seriously early on and built a couple of powerful project template add-ins that addressed just about all of the concerns. Unfortunately these tools didn’t make it into the shipping product of Visual Studio 2005. Shortly after the VS2005 release, Microsoft released Web Deployment Projects (http://msdn.microsoft.com/asp.net/reference/infrastructure/wdp/) as an add-in that you can download. They address the deployment process by combing the jumble of files that the ASP.NET 2.0 compiler (ASPNET_COMPILER.EXE) creates into a single assembly, along with the ability to create repeatable installs. Shortly after Microsoft released Web Deployment Projects, they introduced a second tool called Web Application Projects (http://msdn.microsoft.com/asp.net/reference/infrastructure/wap/) that essentially brings back a full project model similar to VS2003, but with significant enhancements. Both tools recently were released as V1.0 products on the Microsoft Web site.
The Good Things in Stock ASP.NET 2.0 Projects
You may be wondering what all the fuss is about. Stock ASP.NET 2.0 projects may work well for you and if they do, there’s no reason to switch or add any tools. I would argue that no matter what you do, deployment (short of in-place installation with source code) can use the help of Web Deployment Projects, but you only need Web Application Projects if you’ve hit some of the snags of stock projects or you simply like the more standard approach that it offers to project management.
Stock ASP.NET 2.0 projects are nice in a lot of ways. One highlight of the new stock model is the ability to use file-based projects that require no configuration to open a project. You simply point Visual Studio at a physical directory and open it up. Right-click on a page, select View in Browser and the built-in Web server starts up and you’re running the Web application. Look Ma, no hands!
Along the same lines, you can make changes to the code of a page, save the page, and run it in the browser without having to recompile it. I know, I know-no compilation? Blasphemy! But I have to admit I got quite used to not compiling my stock projects and simply running pages after changes. This scenario is even nicer if you have the debugger attached to your Web application. You can now make changes to your code while the debugger is attached, refresh the page, and see the refreshed code in the debugger. No stopping the debugger, no restarting your app. This can save a lot of time.
The final improvement in the compilation model comes if you are using CodeBeside pages-the new partial class model eliminates all of the control definitions from the source code of your classes and instead generates them at runtime. There’s no code clutter of control and event definitions as there was in ASP.NET 1.1 CodeBehind pages in InitializeComponent, and no longer are there issues with Visual Studio mucking up the control definitions or event hooks because that task has been offloaded for ASP.NET at compile time.
All of this is easy and makes getting started with ASP.NET 2.0 easier than what you had to go through with ASP.NET 1.1. It’s surely the main reason why Microsoft went through the trouble of cooking up a whole new compilation model to make ASP.NET more approachable.
Stock Projects: A Few Problems
When I first started using 2.0 Web Projects I was pretty excited. Indeed it did seem much easier to work in 2.0. Especially the Edit and Go functionality and the ability to simply open a project seemed nice, especially as I was checking out a lot of sample projects at the time. I started with 2.0 early in the beta and like most people who used these early versions of the time, I was just trying to understand the many changes by creating small samples and pages. And ASP.NET 2.0 and the stock project model worked awesome for that. I never really got around to a final compilation of my samples for deployment, and most if not all of my work was with single pages that didn’t have external dependencies or complex page class hierarchies. Life seemed good…
Fast forward to the final betas. By now I was getting more familiar with ASP.NET 2.0 and decided to port one of my more complex applications to 2.0. At first I found that the migration didn’t go very smoothly-the migration tool missed many of the pages that were inherited off custom Page classes or pages that referenced CodeBehind classes of other pages. At this point, some of the differences between the CodeBehind and CodeBeside models became clear, and it took quite a bit of time and experimentation to understand just what you can and can no longer do when dealing with page inheritance. Due to the new compilation model, ASP.NET compiles some classes after the initial compile cycle, and that makes it somewhat difficult to reference these classes in code. In addition, I also had to learn where to put files. Could I leave it in my Web directory or do I have to put it in APP_CODE? Will ASP.NET generate my controls or not? Depending on where the page is placed it will vary.
Most of these issues during conversion had to do with ASPX pages that use inherited page classes. I have a number of pages that use a CodeBehind class that serves a number of ASPX pages. This is not easily done in ASP.NET 2.0 unless you create your own control definitions at the base class level (which is a fair amount of manual work), or you resort to using FindControl() in the base class. It took a lot of trial and error to figure out exactly what you can and can’t do with page inheritance-some things that worked just fine and logically in the previous version of ASP.NET just didn’t work in ASP.NET 2.0. The process is not easy and although I now have a pretty good understanding of how the page model works, I think it’s horribly confusing and riddled with inconsistencies and workaround implementation details that developers should not have to deal with. CodeBehindBaseClass anyone?
At the time I figured I was upgrading and I didn’t do things the ASP.NET 2.0 way and that probably accounted for the problems. However, even as I started new projects from scratch, I ran into these same quirks over and over again. In most cases I was able to work around the issues, but because of the complexity of the model, it wastes a lot of my time to get around them. For example, have you ever tried to create two master pages and inherit one of them from the CodeBehind class of the first? You can do it but it’s not very obvious. Or, for example, maybe you need to load a user control dynamically but you can’t have a @Register tag on the page? Simple things like this shouldn’t require any special directives or resorting to reflection or FindControl() semantics to get a proper reference to a type. ASP.NET 1.1’s model was simple and elegant and inheritance worked the way you expect it to, whereas the 2.0 model seems too clever and full of workaround hacks and directives to force things to work a certain way. If you have done any cross page/control referencing, I bet you have run into these issues and wasted a fair amount of time trying to find the right combination of directives and inheritance to make it work. It shouldn’t be this hard!
I’m also shocked by ASP.NET 2.0’s deployment options. When I finally got around to deploying to a staging site, I was stunned by the number of choices I had to make. Should I precompile? Should I include the ASPX files in the pre-compilation? Should I use fixed names or force assemblies to be created for each directory? And the deployment tools built into VS.NET 2005 are pretty lame because they don’t even give you access to all of the options available in the ASP.NET compiler. If you want all the choices you have to use the command line compiler and figure out one of the 20 or so compilation combinations you can come up with through the various options. In fact, I got so frustrated with the options I ended up building a front-end GUI tool for the ASPNET_COMPILER.EXE (http://www.west-wind.com/tools/aspnetcompiler.asp) which let me experiment a little more easily with the options and see the results.
It took me a couple days of experimentation and reflection on the concepts to find a model that I could work with and manage my site reasonably efficiently. Reasonably… the process was far from optimal and involved deleting all existing files in the BIN directory (50 files just for the Web app plus the satellite assemblies) then recopying all of those files into the BIN directory. The worst part, though, was that the install was not repeatable-every build created a different set of deployment files with unique names in the BIN directory. The only way to manage deployment was to delete all the files and copy them back up even if I had only a single change.
Updating your site in real-time is also a problem because of this model. ASP.NET 2.0 has binary files that it must update, and while the update is in process, the site becomes unstable and results in errors on a live site. ASP.NET 2.0’s workaround solution: Use a placeholder file while the update is in progress-Riiiight.
I gnashed my teeth and told myself, “I can live with that. After all, I don’t deploy that often.” But after going through these steps with a few minor updates, finding a small bug with the update and then having to go through this process again, let me tell you this process became more than a little annoying and a considerable time sink.
To make a long story short, over time I’ve gotten very discouraged with stock Web projects for real project work. I still prefer stock projects for samples and simple projects, but for anything critical I’ve moved on to Web Application Projects.
Luckily Microsoft heard these and other serious complaints (no build actions, source control limitations) from other developers and responded with Web Deployment Projects and Web Applications Projects.
Web Deployment Projects
Web Deployment Projects addresses only compilation issues and it works in combination with stock projects. You can also use WDP in combination with Web Application Projects to provide for pre-compilation of ASPX pages in those projects (more on this later).
WDP gets added to an existing solution that includes a Web project. You add a new Web Deployment Project and this new project manages the compilation and publishing of your project to a specific directory in a similar way that the Publish feature does, but it provides a number of useful enhancements. WDP still uses the same compilation that ASP.NET 2.0 uses natively and then post-processes the output generated by the stock compiler.
The key feature of the WDP tool is that it can create a single assembly of the mess of files that the stock project creates. It still doesn’t create just a single file-there are still .compiled marker files for each page if you chose to precompile the ASPX pages as well.
But unlike stock projects, all the files generated use fixed hash values for file names, so the installs generated are fully repeatable. For example, if you compile to a single assembly, the single assembly will be the same name, and each of the .compiled files for the ASPX pages will have the same name as the previous build.
This means that now when you deploy, you can, in most cases, update the single assembly and leave the other files alone. You’d only need to update the .compiled files if you add new files to the project. So if you need to make a minor fix after you deploy to the live site, you can now update a single file.
A single assembly also means that you are updating a single binary file on the server, which again makes it possible to do an in-place update of the application without shutting down the server and without seeing error messages while the assembly is being updated.
Because WDP is a real Visual Studio project, it is a straight MSBUILD file that you can trigger for automated builds, which was one additional complaint with stock projects. You’ll also discover a number of useful features in WDP that allow you replace sections in Web.Config with content from external files. This lets you change your config settings for deployment which are almost surely going to be different from what they are in your development environment. You can also assign version information to the assembly you created. Previously, the best you could do is store an AssemblyInfo.cs file into your APP_CODE folder which would give a version to the generated APP_CODE assembly only.
If you plan to use stock projects with ASP.NET and you plan to deploy a pre-compiled Web site, I highly recommend you combine it with Web Deployment Projects to create workable installs.
Web Application Projects
To address the main logistical issues with stock projects mentioned above, Microsoft has provided Web Application Projects (WAP). WAP basically takes us back to the compilation model that Visual Studio 2003 used with some important enhancements and full support of all the ASP.NET 2.0 features. WAP brings back the CodeBehind compilation model, where all CodeBehind code gets compiled by Visual Studio into a single assembly in the BIN directory. When you build your projects you get a fully compiled, single assembly and an in-place installation that is fully self-contained.
WAP is provided as a Visual Studio Project project template. To create a new project, you Create a new Web Application Project which creates a familiar .csproj or .vbproj file. Unlike VS2003 though, the new project doesn’t use FrontPage extensions, but rather accesses the files directly from disk, so it’s much faster. The project is a full Visual Studio-style project with all the features you’d expect from a project like XmlComments, versioning, compiler switches, build actions, etc. And like you expect with any VS.NET project it’s also an MSBUILD script so you can customize as needed with all the functionality MSBUILD allows.
If you already have a stock ASP.NET 2.0 project, you can use the Convert to Web Application option to automatically convert the project for you. The converter runs through your project and fixes up each of the ASPX/ASCX/MASTER pages, updates the CodeFile tags to CodeBehind, and adds the new .designer file with the control definitions. I ran into a few issues with this conversion option not being able to find control assemblies in the BIN directory. I suggest that you compile your existing project under stock projects just before doing a conversion to ensure all the required dependencies exist in the BIN directory.
WAP works like VS2003 projects in that it uses the project file to manage the files that it can see, so rather than simply looking on disk and blindly pulling everything in the directory into the project, WAP only holds what you add to the project. So you need to add any files you want in the project, even if they exist on disk. You can also use WAP and exclude files to remove them-another feature you couldn’t do with stock projects.
The key WAP feature in regards to compilation is that it moves the step of control code generation of the ASP.NET page process back into the designer-WAP controls and pages are made up of three files that make up each ASPX/ASCX/MASTER page (C# files shown here):
- The aspx/ascx/master markup file
- The .aspx.cs file that contains your CodeBehind code
- The .aspx.cs.designer file that contains the control definition
If you’ve worked with Windows Forms 2.0, you’re already familiar with this model where your code goes into one file (the plain .cs file) and the designer-generated code goes in the other (.cs.designer). The generated code consists merely of the control definitions for the page which gives the base class the proper signature and reference to the controls. This is an important shift because with this mechanism the class name is known at original compile time and the class is available in the current, single assembly of all CodeBehind code, so Page and Control classes can be easily referenced across the entire Web application.
Visual Studio 2005 now compiles these two classes together into the base class. The result of this is that the code generation for the control definitions is no longer delayed until runtime and ASP.NET doesn’t need to generate a unique classname for the base class. In fact, all page and control classes compiles into a single assembly for all CodeBehind classes. Any page class can access any page or control or master class by its CodeBehind type as you’d expect because the type now exists at initial compile time and lives in the same assembly.
This simple change solves the problem of cross-page referencing of controls and pages, the various inheritance-related quirks, and it also makes for a much more speedy compilation process. Compiles of a moderately complex project with 50+ pages takes about one second with WAP vs. 20-25 seconds with stock projects. If you compile a stock project, the process is excruciatingly slow because ASP.NET actually compiles the entire project including the ASPX files and copies it out to a deployment folder. With WAP, a compile only compiles the CodeBehind code-there’s no ASPX parsing and the compilation is in place and results in a single assembly that is placed in the BIN directory.
Web Application Projects also support Edit and Continue, which was a feature that Microsoft squeezed in at the very last minute. Edit and Continue gives you some semblance of the Debug and Go functionality of stock projects. Truthfully though, I’m not a big fan of Edit and Continue; the fact that all but the active source files are locked and inaccessible for editing really is more hassle to me than it’s worth. But if you’re already using Edit and Continue in Windows Forms or library projects, you can expect similar behavior with Web applications now. Again, consistency is a virtue.
Web Application Projects and Web Deployment Projects in Combination
On the downside, WAP requires compilation of any changes, so you can’t simply execute pages after a change. Using WAP means that you’ll use Ctrl-Shift-B more frequently to build your Web project. Fortunately the compile is fast.
You can no longer get error detection inside of ASPX pages with WAP alone because the compiler only compiles your CodeBehind classes and not the markup code, so errors there don’t show up in the Error display. However, if you still want this useful feature, you can use WAP in combination with Web Deployment Projects and pre-compile your markup pages. WDP compiles the markup pages and can also flag the errors in its compilation error display. This compile is slower like stock projects, but it’s a great tool to run at least from time to time and ensure that your expression markup is valid in markup pages.
Web Application Projects Are for Me
I’ve spent a fair amount of time now both with stock projects and Web Application Projects and I can tell you that I feel much more comfortable and productive with WAP than with stock projects. Everything just works as you would expect and I’ve not run into any issues of things that don’t work. It’s a predictable and proven model that is based on standard .NET principles that anyone who can look at the output generated can easily understand.
If you are building reasonably complex projects, I think you too will find that this model is a better fit for the way most developers work, even though the model is more rigid. Most importantly, it’s consistent with the rest of Visual Studio, and not an oddball project type and an oddball compilation model with many intricate clever tricks to make it work and that you as the developer have to understand.
I do not doubt that some developers are happy with stock projects too, and if they are working for you, and, unlike me, you are not running into the boundary cases I mention above, by all means stick with stock projects. They are less rigid to work with and the projects are more portable. If I build any sort of demo application or samples, I will surely use stock projects.
If you run into a problem with stock projects that you can’t solve, you can now easily switch to WAP if necessary. The conversion isn’t completely automatic, but you can do it fairly quickly. Even with some of the compiler issues I had in my conversion I ended up converting the 50+page project in about an hour.
You can also go from WAP back to stock projects although this is a manual process. You can find out more here: http://west-wind.com/weblog/posts/5571.aspx. I suspect there will be little need to go this direction.
Community Driven
I think that Microsoft did a bang-up job getting these tools out to solve the problems with stock projects as they became apparent. Both WAP and WDP were very publicly discussed and Microsoft listened very carefully to community input during the development cycle. Microsoft added many features after the initial releases came out due to public community input. Each new release during the preview cycle brought many of these new changes very quickly. It’s good to see this kind of flexibility at Microsoft after dealing with the slow-as-molasses monster releases of Visual Studio .NET during the betas.
It would have been even better if WAP and WDP had made it in the box, but given the timeframe of release that wasn’t possible. As it stands, these tools will become part of Visual Studio 2005 SP1 later this year and future releases.
Note though that neither of these tools work with Visual Web Developer (VWD) currently, and I don’t believe there are any plans to integrate them into updates in the future either. VWD developers will be stuck with stock projects, which is probably OK given the scope of VWD.