Well... a lot has happened since my original Blog on the subject of ASP.NET 2.0 migration. A trip to Redmond and numerous discussions with members of the ASP.NET Team revealed that we really only had one path to pursue. And we have made a great deal of progress in the past few weeks, proving the model will work, and dealing with issues as they surface.
So let's revisit the 3 options I discussed earlier:
Virtual Directories - map virtual directories to all subfolders within the Web Project.
- as it turns out, some of my original comments on this approach are not entirely accurate. If we consider the development and run-time as 2 completely different scenarios - and we only consider the VDIR approach for development, then the argument regarding deployment to a hosting environment is not valid. That being said, this solution is still far from optimal ( I would actually go as far as calling it a hack ). One of the key goals in DotNetNuke has always been to simplify the development experience ( we are a Web Application Framework afterall ). By requiring module developers to use VDIRs to partition their code during development, increases the amount of configuration required and ties our development model to IIS ( which is no longer even the default web server in the VS 2005 IDE ). In reality, Microsoft added support for VDIRs in ASP.NET 2.0 to preserve the behavior for applications which were architected to use this pattern in ASP.NET 1.1 - not to consider it as a new architectural pattern for applications in ASP.NET 2.0.
Class Library Conversion - the root web project could be converted to a class library project
- although this approach seemed to be the best option in our initial migration testing, it ultimately had some serious issues when we pursued it further. Converting our root web to a class library allowed us to migrate with minimal effort and achive run-time compatibility on ASP.NET 2.0. However as soon as we tried to develop new modules under this paradigm, we ran into difficulty. This is because there is no longer an option in VS.NET 2005 to construct web user controls with code-behind like you used to in VS.NET 2003 - with designer support and event hooks. In VS 2005 there is now a very clear delineation between writing Web Projects and Class Library Projects - and the paradigm we use today which leverages a mix of the two, is unsupported in VS 2005. So basically, although ASP.NET 2.0 supports the run-time of this model, the VS 2005 development tool does not let you develop applications in this way. The end result is that people would need to continue developing in VS 2003 or use a third party IDE like SharpDevelop or an external compilation utility - none of which seeme like viable options as we move forward.
Web Project Reorganization - the folder structure for DotNetNuke could be re-organized to conform to the new Web Project model.
- considering the list of issues outlined in my earlier Blog, you would conclude that this option is not viable either. However the fact is, this option ended up being our only remaining alternative. This is mainly because the VS 2005 IDE forces us down this path whether we like it or not.
So lets talk about fundamental goals of the ASP.NET 2.0 migration:
- we want to preserve our modular architecture - the ability to abstract and plug-in functionality is fundamental to our Web Application Framework architecture. Essentially this means that we must have a way to create granular assemblies for various application services.
- we want to ensure run-time support for resources ( modules, skins, providers ) developed in ASP.NET 1.1. Esentially this means that we want our current resources to install into an ASP.NET 2.0 environment and have 100% compatibility with the new platform. There are a number of obvious reasons for this goal. First, we do not expect everyone to upgrade to ASP.NET 2.0 when it is released - therefore we want to provide a mechanism for developers to create resources which can target both platforms ( without requiring multiple versions ). Second, it was only 8 months ago that we released DotNetNuke 3.0 with massive breaking changes - forcing module developers to upgrade their components - and we can not realistically expect module developers to embrace another breaking release.
- we want to improve some aspects of the development model for DotNetNuke. Although we have a very robust portability and distribution specification for commercial modules today, it does not address the Rapid Application Development ( RAD ) requirements of programmers creating custom web applications within their intranet or corporate environments. Where we tend to support a single development methodology today, we would like to offer a number of powerful alternatives which address the diverse needs of a variety of different stakeholders.
This leads to to some deeper discussion on the Web Project model. The Web Project model in ASP.NET 2.0 is not just a subtle behavioral change which you can optionally choose to leverage in your next generation web applications - it is a fundamental architectural concept which completely changes the way you need to approach web application development. It is not just a couple minor tweaks to the ASP.NET 1.1 model but rather a combination of many new concepts woven together to produce an entirely new model. The marketing message which has been publicized as the justification for this paradigm shift seems to indicate that Microsoft was trying to restore some of the simpler, more dynamic attributes of the classic ASP model to the ASP.NET framework. And while it could be argued by many that discarding the "spaghetti" aspects of the classic ASP model was a good thing, there is also a counter-argument which suggests lowering the barrier of entry encourages more developers to adopt a platform ( just look at the PHP/Perl community ). Arguments aside, ASP.NET 2.0 will be shipped November 7 and we need to do our best to understand the full ramifications right now.
So the first thing to understand about Web Projects is that there can only be one per application ( unless you are using VDIRs - but we already covered that above ). Since the Web Project model is based on the file system rather than a manifest ( ie. a *.vbproj file in ASP.NET 1.1 ), you need to view a Web Project as a "silo" - a root folder which contains subfolders and files - ALL of which are considered to be part of the same Web Project. By default this also means that ALL files are part of the same assembly. This definitely poses a problem for DotNetNuke in its current form. Currently DotNetNuke organizes ALL of its resources - web and non-web - beneath a single root folder and uses project files in each folder to instruct the VS 2003 IDE how to group the files for compilation into multiple assemblies. This leads to the first fundamental change which needs to occur in order for DotNetNuke to be successfully migrated to VS 2005.
Old folder structure:
\root* - contains all web and non-web resources
\bin
New folder structure:
\root
\lib - contains all core class libraries and is not deployed to the run-time environment
\web* - contains the Web Project ( binaries, modules, skins, etc... )
\bin
At first glance this does not seem very complicated. But the reality is that the location of the website has changed ( denoted by the "*" ). This becomes especially challenging when you consider the upgrade scenario for users of DotNetNuke on ASP.NET 1.1. There are a lot of files/folders which need to be reorganized - some of which we know about - and others we don't ( ie. resources added by third parties ). And there are different upgrade scenarios to consider as well ( ie. are we upgrading a run-time or development environment ). This is going to be one of the most challenging aspects of the migration effort.
An interesting benefit to the above structure is that it better abstracts our "Core" application from its web/content resources. From an architectural perspective, this definitely seems to be an improvement over what we have today. In fact it may allow us to more easily create some new packages for different stakeholders ( ie. for the group who wants to treat the "Core" as a black box and does not need source code ).
As I mentioned in my earlier Blog, I am not a believer in "change for the sake of change". Therefore, I want to reveal the fact that we have been able to discover some real business benefits offered by the Web Project approach. The benefits mostly relate to the additional flexibility which the Web Project model offers - flexibility which can allow us to support a number of additional RAD development techniques.
In my opinion it is best to discuss ASP.NET 2.0 in terms of scenarios:
1. Static - an end-user is using DotNetNuke as a portal solution. In this case there are no development requirements and no source code - it is simply deployed to a host/server.
\web
default.aspx
web.config
\app_GlobalResources
GlobalResources.resx
\bin
DotNetNuke.dll
Module.dll
\DesktopModules
\Module
ViewModule.ascx
EditModule.ascx
\app_LocalResources
ViewModule.ascx.resx
EditModule.ascx.resx
\Portals
...
This looks exactly the same as our run-time picture for ASP.NET 1.1 and in fact, it will support modules developed in both ASP.NET 1.1 and 2.0.
2. Dynamic - a developer wants to be able to make modifications directly to the site and leverage dynamic compilation.
\web
default.aspx
web.config
\app_code
\Module
Module.vb
\app_GlobalResources
GlobalResources.resx
\bin
DotNetNuke.dll
\DesktopModules
\Module
ViewModule.ascx
ViewModule.ascx.vb
EditModule.ascx
EditModule.ascx.vb
\app_LocalResources
ViewModule.ascx.resx
EditModule.ascx.resx
\Portals
...
This model emulates the classic ASP model. You can make changes to any of the *.ascx or *.vb files in place ( or upload new files over top of the them ) and ASP.NET 2.0 will recompile them dynamically the next time they are requested ( there is no need to pre-compile ). This development methodology can be used in the entry level tools such as Visual Web Developer. This would be a good RAD model for custom web application development. Please note that the code files must be deployed in this model - so if intellectual property protection is important ( ie. commercial modules ) then this may not be optimal.
3. Commercial Module - a developer wants to develop commercial modules with the IP protected which can then be packaged and deployed into other DotNetNuke implementations.
\module_web
web.config ( with pre-compilation option turned on )
\app_code
Module.vb
\bin
DotNetNuke.dll
Module_#hash#.dll
\DesktopModules
\Module
ViewModule.ascx
ViewModule.ascx.vb
EditModule.ascx
EditModule.ascx.vb
\app_LocalResources
ViewModule.ascx.resx
EditModule.ascx.resx
\web
...
This model uses a seperate Web Project so that it can compile all of its module resources into its own assembly. In order to do this you need to enable the pre-compilation option. Once you are satisfied with the module, you will need to package all of the resources into a DotNetNuke PA package ( the same way you do today for ASP.NET 1.1 - dll, ascx, resx ). Then it will be deployed into the run-time environment as per #1. This development methodology can be used in the entry level tools such as Visual Web Developer. A bonus to this approach is that you could actually include a test harness page ( ie. text.aspx ) into the root of the module_web which can be used for testing your module independently from the DotNetNuke portal framework.
4. Class Libraries - if a developer needs to create a Provider or an assembly with a custom name.
\lib
\DesktopModules
\Module
Module.vbproj
Module.vb
\bin
Module.dll
\web
...
Web Projects do not allow you to create assemblies with custom names. Instead they generate their own assembly names ( the format depends on whether you are using the FixedNames options or not - but either way the name contains a hash code which is autogenerated ). When you are creating components which are dynamically invoked using Reflection, you often require a full TypeName - which requires an assembly name. Sounds a little like the recursive chicken-before-the-egg dilemma, doesn't it. To solve this problem, you can use Class Library projects exactly the same way you did in VS 2003, as they provide the means to custom name your DLLs. The only caveat is that you can not create Class Libraries in Visual Web Developer ( you need VB Express or a more advanced VS 2005 SKU ).
The item identified in #4 above is actually quite a dilemma in DotNetNuke. In order for modules to be functional in DotNetNuke, they typically have some type of data access requirement. The Data Access Layer ( DAL ) in DotNetNuke is designed using a Provider model which allows for portability of the application across multiple database platforms - all it requires is that a developer create a Provider implementation for the platform they are targeting. The Provider management logic within the DotNetNuke Core uses a combination of config file settings and Reflection to dynamically load the appropriate DAL at run-time. This model requires custom assembly names. So in order for a developer to create a DAL for their module, they will need to create a class library project in addition to their web project. This is not really convenient - but it is no different than what needs to be done today in ASP.NET 1.1. And we are investigating a number of concepts which would allow for a more simplistic DAL development model - but this still requires some more research. DotNetNuke also has a number of optional interfaces which are implemented in their BusinessControllerClass - which also requires a custom named assembly. It would seem that if Microsoft added the ability to custom name assemblies in Web Projects, it would be a valuable feature ( but I am not holding my breath ).
On a different topic, I am very pleased to announce that vast portions of the DotNetNuke architecture are completely unaffected by the ASP.NET migration. For example, the DotNetNuke skinning architecture requires no changes whatsoever - so web designers creating skins for DotNetNuke today will have no impact as we move to ASP.NET 2.0.
Anyways, that brings you up to date on the latest migration status of DotNetNuke to ASP.NET 2.0. I hope you found this useful...