At work, I’m redeveloping the old, ASP 3.0 CMS application and replacing it with a shiny new .NET 3.5 implementation. The software is designed to be run as a virtual directory from all websites, and thus shares the same from installation to installation.
The old CMS is a mutant. It started as an ASP 3.0 application, and then had extra bits made of .NET 1.0 & .NET 2.0 tacked on to it, much in the same manner that Frankenstein’s monster was created. The core ASP 3.0 application handled the page/news creation and publishing, and served as the interface.
The additions were mostly in the form of user controls (.ascx files) that were placed in the content for a page that needed one. These user controls took care of things like random image rotators, contact forms, bread crumb menus, etc. Various sites used a various sub-section of a pool of controls.
The modus operandi with the current system is that each installation has it’s own collection of controls which are inserted into pages by us on behalf of the client, because it involves putting ASP.NET markup into the content areas.
I’ve decided this isn’t such a great idea, and as such, I’m centralising the user controls as a library, seperate from the CMS, so that each site accesses the single pool of controls, and if a client leaves, it will be relatively simple to recompile a new library with the controls they use.
Anyway, that’s the back story. Essentially what I need to do is compile a whole load of .ascx files into a dll, and load them into pages. I’ve spent all morning looking on Google for tips on how to do this. And frankly the results were less than helpful, however I have a history of not reading documentation properly.
What I found out you need to do, is to add a class library project to your solution, and add the .ascx file as per normal. However, you need to do several steps to get this working properly:
- Go to the properties of your .ascx file and change the build action to Embedded Resource.
- From your control declaration on the .ascx file, delete AutoEventWireup. We need to wire these things up ourselves. Personally I cleared it of everything except the language attribute.
- In the old code behind (now unattached class file) for the .ascx, you need to override the OnLoad event handler, and put the following code:
string content = String.Empty;
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), “example.ascx”);
using (StreamReader reader = new StreamReader(stream))
content = reader.ReadToEnd();
Control userControl = Page.ParseControl(content);
This source will use reflection to open the currently executing dll (in this case, our .ascx library) and find the content for the .ascx, parse it as a new control and add it to the currently executing context.
- For every control on the .ascx, in our now orphaned .ascx.cs you need to declare a private/protected variable of the same time, with the same variable name as the ID on the control (for sanity’s sake). You need to find this control in our newly loaded .ascx and assign a reference:
labelInAscx = (Label)control.FindControl(“labelInAscx”);
- The above two steps is exactly what the AutoWireUp attribute on the control declaration does for you. We do it manually because we have to use reflection to extract the content of the ascx file, which is compiled into our dll.
After taking these steps, compile your project, and in another project, on a regular aspx page, register the assembly and use as you would any normal .ascx and hopefully the content will render out fine.