One of the favourite Enterprise development strategies for .NET websites I've come up with is that of splitting the website into logical areas along functional- (and naturally change-) boundaries; having separate areas of the site developed as separate ASP.NET controls. I'm not talking small-scale controls like "Address entry" here, I'm talking entire 5+ page application processes as a single control (that might itself comprise further controls). This model works well for all kinds of large organisations - an online e-commerce site could have separate basket, checkout-process, and product-search controls, for instance, each of which would be aligned against a set of services that they're consuming (in an SOA). The current enterprise-in-question is a bank, which fits this model better than most other sites I've come across due to the sheer amount of functionality necessary on the website, and its diversity. Application forms alone constitue a raft of controls:
- Mortgage applications
- Credit card applications
- Personal loan applications
- Motor insurance applications
- Etc.
My view on coordinating this has been, for some time, to have separate teams working on each "control", basically becoming product teams that deliver a black-box control to one overall "site" team. It is then this team's responsibility for plugging all of the controls into the main site, maintaining all the links between areas, etc. There are several benefits to implementing an enterprise-class site this way:
- It gives a simple way of logically breaking-down/grouping a large number of development staff
- It supports concurrent development on multiple parts of the site. Because the controls don't know about each other, there's no risk of them linking to one another and dependencies being created. This allows for varying rates of change in different areas, and doesn't predicate large-scale upgrades when a new version of some base functionality becomes available
- It provides a black-box component that allows for alternative internal implementations, for instance migrating from an HTML based UI to a Macromedia Flash one, and eventually to a Longhorn one.
- It matches a model of having multiple levels of continuous integration, rather than having a single-level uber-integration that becomes unwieldy
That's the good news - a paradigm for developing enterprise websites that theoretically has few drawbacks. Moving on to the implementation is where the bad news begins...
In .NET, these controls could either be developed as user controls (.ascx files), or as custom controls (.cs files). The advantage of the former is the speed of development, and close integration with UI designers - developers can work in "HTML view". The latter involves writing all content as controls. A short example of this is as follows:
Web control implementation:
<h1>Hello World</h1>
<asp:TextBox id=txt runat=server />
Custom control implementation:
Literal literal = new Literal();
literal.Text = "<h1>Hello World</h1>";
Page.Controls.Add(literal);
TextBox txt = new TextBox();
txt.Id = "txt";
Page.Controls.Add(txt);
Although possible, developing a graphically compelling site using the second method is torturous, so I've discounted it as an option. I also don't want control teams to deliver an editable ASCX control to the site team - it would be prone to editing, etc. and not as much of a "boxed product". There is an alternative, however. Whenever .NET renders a web page that makes use of a user control, it converts the first code example into the second internally. In Visual Studio .NET 2002 and Visual Studio .NET 2003, this process is largely invisible, and only happens when the page is requested. Visual Studio .NET 2005 ("Whidbey") changes this, though, allowing for pre-compilation of websites into Assemblies (DLLs).
So, my long-term plan was to have each team develop a control in a separate VS.NET 2005 project, pre-compile the output when they're ready to release, and then just hand the Assembly over to the "site" team to use just like any other class library. Having spent many, many hours over the last week poking and prodding the aspnet_compiler.exe tool, rewriting it from scratch, attempting reflection on the System.Web.Compilation namespace, and even disassembling most of the System.Web assembly, I'm getting close to giving up. Rather than creating one sensibly named assembly for the whole project, the compiler creates multiple randomly named assemblies - usually one for each control/page (although it sometimes puts several together). After recreating the aspnet_compiler tool from scratch, and extending it to sift through these files, pull out just the assemblies, give them new file names based on the controls they contain, etc. I thought I was getting somewhere. Now the problem is that if one of these controls uses another from the same project, it will be given a reference to the random 8-letter assembly name (and matching internal module name). I've yet to see if any internal assembly hacking can rectify this.
None of this would be necessary if Microsoft hadn't specifically made the majority of the System.Web.Compilation namespace private/internal, presumably in an attempt to make it difficult for other people to develop competing tools, etc. The most infuriating part of this is that, in theory, you can access all of the System.* functionality through reflection, whether its supposedly private or publicly visible. Additionally, tools like Salamander and Reflector make it possible to decompile vast swathes of the system classes back into C#. So Microsoft aren't really "protecting" anything, they're just making it painful to come up with enterprise class solutions.
The point to this post?
- Here's a model for enterprise web-site development that works, even if it DOES mean handing over controls that aren't totally black-boxed.
- If anyone is a System.Web.Compilation guru and fancies helping out on creating a tool to enable this, please mail me
- If anyone thinks that Microsoft should make it easier to compile source code, please mail them