Today I'm starting a series that I'm calling "Old Code". This will be where I go over some project I've worked on that was notable for some reason but may not directly translate into a "how-to" for developers today. These posts will more be about some problem to which there was no simple solution but to which a solution was found that was usually either particularly creative, cutting edge (for its time) or a total hack but that got the job done. Some of these projects I'm proud of, others I'll be telling you about even if it may not be my best work. Overall though I think we can all gain by looking back at our past projects and letting the public review them
for with us. In most of these I won't be able to provide code samples or even give application / company names because of NDAs but I don't think that will impact the overall posts.
I this first installment I'm going to be talking about a project I was working on about four years ago. Disclaimer: My memory of 2004 may be a little fuzzy but I don't think I can take full credit or blame for this solution.
Background: The overall project was to create a web-based management application for complex devices which did have their own internal memory. Basically this application was to replace numerous desktop applications with a multi-user, accessible anywhere, cool, user-friendly, do everything management application. When the project got started it was 2004 and we were building it in C# and ASP.NET on the .NET 1.1 framework.
Problem: Of these devices that the application was to manage there are numerous 'families' to which the capabilities of and communication to are drastically different. This application was to allow the ability to be installed with the ability to support one or more family and have the ability to support future families possibly being added by third-party developers. They didn't want to release the source code or to have to recompile every time a new family was to be added. In theory a third party company that makes these devices would have the ability to create their own "plug-in" and install it at a customer location without our companies involvement.
Issues: With it being 2004 none of us had a ton of .NET experience but we did know a lot. To our knowledge (and I still think this was true in 1.1) all code-behind files for a web app were compiled into a single DLL at build time. This is where the real issue existed: How do we let third-party developers seamlessly add pages to our .NET 1.1 web application?
Solution: Now the architecture that was devised to handle this is hard to explain without examples. Who am I kidding, it's hard to explain with examples. Many good developers took months to really grasp what we were doing, we'll see if you get it quicker. Basically the application was split into pieces. It was already n-tier with a full business object model based on Lhotka's CSLA framework. Basically an architecture was created in which any family specific code would exist in satellite dlls that are loaded using reflection at run-time based on information coming from the SQL Server database. This included the code-behind files for any pages or user controls that contained family specific controls/data. Much work was done to construct generic widget classes that only contain fields that all widgets have regardless of family and then having the family specific classes derive from those classes and add their own fields / methods as well as all update logic. While that is standard for OO business layer development, it's something else to apply that same paradigm to web pages.
We ended up creating a structure where the base application would know that there was a widgetconfig.aspx page. Then at run-time an intermediary page would intercept the request for the config page and append a family specific folder name in front so that the request would get to the correct page. These was still the issue of the code-behind pages. This is where it gets tricky. For each family specfic page the actual aspx would only contain the generic header and footer user control declarations (this was pre-master pages) and a declaration for a user-control of the same name as the parent page. In the directive for the family specific user control the assembly would be named to find the class in. This assembly was a family specific dll that housed all code-behind files for that families pages. In the class for that user control it would name the actual .ascx file to associate with the controls defined in the class.
Through this method we were able to create a way to add a new family to an installed server by adding some dlls to the bin and some code-less aspx & ascx files to the application folders. So it was possible to do this without touching the original source.
Conclusion: After much coding effort and even more in education this strategy went untested for nearly four years. Just today we got word that the first true use of this plug-in model had been successfully implemented using our SDK and without touching our source code. While I'm sure that there were probably more elegant ways to accomplish this and that I'm glossed over much of the complexity this was a solution for the problem that worked. Of course in .NET 2.0 it would have been much easier, but that didn't exist yet. I was going to have a co-worker from that project review this before I posted it but what the hey, he can review it by reading it :).
Don't worry, some posts in this series may contain actual code :).