So I bit the bullet today and decided to switch over my West Wind Web Store to use Web Application Projects. After having hit so many weird issues with trying to build dynamically loaded controls and Master Pages I've finally decided this is simply not going to work efficiently with stock ASP.NET projects in 2.0. Specifically I could not find a viable working solution to the Master Page theming scheme I came up with, without base classing every Master page and adding any controls manually to the base class. No thanks. <s>
Going back to the single compiled assembly solves all those funky problems that I've been encountering at the cost of going – at least for now – a non-standard project route and of giving up some of the ease of use compilation and debugging features in stock ASP.NET 2.0 projects. I think I can live with that. We'll see.
Here's a progress report on the conversion process of this project.
Scott has posted some excellent walk throughs on the process of conversion which I used as a reference to start. If you plan on doing the conversion of a 2.0 project to WAP be sure to at least read through this if not walk through it as you're doing it.
As a point of reference this project has about 80 ASPX pages scattered over 4 directories along with some mobile forms. There are a couple of HTTP modules and a handful of utility classes as well a quite a few base page and control classes which are stored in APP_CODE.
To start I copied all the files from my existing project into a newly created Web Application Project first, followed by pulling in all the project references. What I did was essentially take my existing project, remove the wwStore project from it, then create a new project in the existing solution and then copy the existing files (using Explorer) and drop them into the new project. I made the various Images directories and Bin directory excluded.
Next I went and added reference to all dependent projects that would bring in the dependent assemblies for this project (5 other projects).
Next I used 'Convert To Web Application' option from the Web project root. The tool then sets out to convert the project's pages and splitting them into the your partial class plus a .designer file that contains the control definitions.
If all goes well at this point you should be able to compile your project and it should come up with no errors. If your project contains many inherited pages that's probably not going to happen with a few minor tweaks.
Of course, since Murphy loves me it didn't go that smooth for me <g>.
External Base Class Problem
All pages in the root directory seemed to convert fine, but all my files in the Admin directory for some reason did not. I then manually reran on the Admin directory's Convert To Web Application at which point a couple of the pages converted but not all. Looking at the classes that didn't convert they are all inheriting from a base class that's not defined in the current project.
Each generated this error:
Generation Designer file failed: Unable to load one or more of the requested types. Retireve the LoaderExceptions property for more information.
(it would really help if this message included some information about WHICH component didn't load)
I'm not quite sure what the actual problem was, but I *think* it's because the BIN directory was empty and WAP is not compiling the dependent projects first so it wasn't finding the appropriate control assembly for some of the pages that are based on an external assembly for the base Page class. However even after copying the assemblies manually from the old project the convert still didn't work (note that compiling the dependent projects also didn't create the BIN assemblies?)
Later:It looks like WAP is NOT copying dependent assemblies into the BIN directory by default – Copy Local is set to false when you add a Project reference. I hope this is not by design… The app surely won't run without the assemblies there.
So I was still getting this conversion error and I started fiddling with one of the pages that werenn't converting changing the class use a plain Page class and that also didn't work. Needless to say this was frustrating – seeing classes with the same layout work and this one simply not going.
By chance I opened one of the pages that didn't work in the designer and resaved it. Then re-ran the Convert to Web Application, and it converted! I tried the whole directory and all converted as well.
Now I wish I could say I knew what I did. My guess is that opening the page in the visual designer somehow caused the external control to be loaded and become visible to WAP where it wasn't before. But that's just a guess… there's some issue where the external controls or at least the page object weren't visible. What's odd is that the base pages that did convert also use these custom controls, but the page base class was rooted in the current project.
IAC, if I had to do this over I would make sure to copy over the BIN directory with the old application regardless of the fact that the new project should overwrite it. In my case the likely culprit too was the Solution Build Order which ended up building the Web Project first, so on first load when running the conversion the dependent assemblies weren't present and a recompile later didn't create the assemblies in the Web Project (until the whole thing compiled successfully). I'm not quite sure why that happens – I would think the BIN dir should always build first?
I ran into another oddity with a 'special' Form in my project (all of my projects for that matter) which is my generic MessageDisplay page. This is a shell class that is based on a control library base class form to handle most of the display logic. It was a bitch to get this thing to work properly under 2.0 standard projects because of the control name inheritance issues. Now going back to WAP is back to the way it worked in 1.x which is a simple inheritance structure.
Unfortuntately the WAP conversion mucked up the link between the APP_CODE stored codebehind class and just removed the Codebehind altogether just inheriting from the partial class. Which doesn't work of course because WAP needs to generate the control definitions into the ,designer.cs file. I had to manually move the file and add the Codebehind attribute into the page.
The old definition with an Inherits to an APP_CODE stored Codefile:
<%@ Page Language="C#" MasterPageFile="~/App_Templates/Standard/WebStoreMaster.master"
Inherits="Westwind.WebStore.MessageDisplay" EnableViewState="False" AutoEventWireup="true" %>
What I ended up with with manual editing and moving the file to the ASPX directory.
<%@ Page Language="C#" MasterPageFile="~/App_Templates/Standard/WebStoreMaster.master"
Inherits="Westwind.WebStore.MessageDisplay"
Codebehind="~/MessageDisplay.aspx.cs"
EnableViewState="False" AutoEventWireup="True" %>
Once I did that I could manually convert it.
I ran into another weird issue in this page conversion. ASP.NET insisted that my control defnitions were duplicated. In fact they were not. And the same thing as above I had to fiddle with the page saving, editing for ASP.NET to properly compile the page.
Further the page and CodeBehind file weren’t properly associated – the project ended up showing the MessageDisplay.aspx and MessageDisplay.aspx.cs file on the same expansion level rather than showing the MessageDisplay.aspx.cs file below the ASPX. No amount of reloading fixed that.
I had to manually edit the project file to make it work. To do this, unload the project file, then edit the XML file. Specifically:
<Compile Include="MessageDisplay.aspx.cs">
<DependentUpon>MessageDisplay.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="MessageDisplay.aspx.designer.cs">
<DependentUpon>MessageDisplay.aspx</DependentUpon>
</Compile>
Notice the DependentUpon tag for the aspx.cs file. It was missing – adding it put the aspx.cs page underneath the aspx file.
Success Overall
Overall this update went fairly smooth <g>. It looks like there are still a few rough conversion edges in WAP related to Page inheritance, but most likely most people won't see that especially if you're not using inherited pages that inherit from external control libraries.
Nevertheless it took a few hours to get it all done.
On the upside – I went through my project and everything ran out of the box without any further changes. So overall the converter is doing a good job catching Pages, Masters and Controls and doing 'the right thing' with it.
And most importantly the reason I switched to this scheme in the first place: My MasterPage Theme switching mechanism based on inheritance. Fired it up and bingo, I can switch themes and see my templated master pages with embedded user controls and all.
For real work – I'm over the 2.0 standard projects. Trying to work through all those funky inconsistencies with page and control referencing – forget it. It's a royal waste of time.
For simple things though standard projects are nice. I do like the simple point and open ability of those projects as well as the ability to run without compile and even debug without stopping to recompile/restart the debugger.
But in the end the wasted time I've had with standard projects simply aren't enough to make me want to use them for any production work.
FWIW, I've also been using WAP in another smaller project I'm working on on the side and it's been working real well, which prompted me to finally take the plunge and convert this app. I've been very pleased with model - well, if you used ASP.NET 1.x you'll know what to expect. Most importantly though
So now I can get back to work and stop wasting time <g>...
Other Posts you might also like