Packaging ASP.NET ASPX Pages into a separate Assembly
As part of the resource provider I’m building there are a few administration pages that are used to provide runtime resource editing features to the application. The idea is that on a page the user can click a link to see all resources on a page and pop up a form to edit the resources and update them. The interface from a simple sample form looks something like this:

All of that works just fine, but I’m wondering how to best package these pages. At the moment what I do is stick the admin pages into a special folder of any project that uses the localization provider and just copy them as is.
While this works fine, this is kind of a hassle to do for anybody who wants to use the component because you end up adding a bunch of files to your project. On the upside the pages can be modified, but on the downside if changes are made it’s easy to get out of sync with updates that might occur in the base library.
So I played around with this a little bit and was surprised to find that it’s quite possible to do this now by using Web Deployment projects. I haven’t done complete testing of this yet, but with some simple tests this just works.
Here’s what I did:
- Created a new Web Application Project (I suppose a regular project would also work)
- Added a new page to it
- Compiled the project made sure it works and runs
- Created a Web Deployment Project for the WAP project
- Set options for a single Merge assembly, and not updateable (ie. Precompiled ASPX code)
- Added a Post build step to copy the two DLLs for the project to the Bin directory of the main
- Created an HTTP handler to invoke the compiled Page
And to my surprise this worked first try.
So here are a few more details. I used a WAP project for testing because I figured it would be easier, but I’m thinking that it’s probably better to use a standard project since it can create a single DLL. WAP projects that get compiled with WDP end up with both the CodeBehind assembly plus the compiled assembly for the page code. Using a plain project would give me a single assembly.
Note that this assembly will be in addition to the assembly for the actual ‘component’ which in this case is the Localization Provider and support controls. I suppose I could put all of that code into either the WAP or Web project, but I don’t like that idea much. If WAP could produce a single DLL I would consider it but I certainly am not going to put my library code into the regular Web project mess<s>.
The post build step in the Web Deployment project looks like this:
<Target Name="AfterBuild">
<Copy SourceFiles="C:\projects2005\subproject_deploy\bin\subproject.dll"
DestinationFolder="C:\projects2005\Articles\Internationalization\Bin" />
<Copy SourceFiles="C:\projects2005\subproject_deploy\bin\subproject_pages.dll"
DestinationFolder="C:\projects2005\Articles\Internationalization\Bin" />
</Target>
To copy the two DLLs from the final WDP output bin folder into the application’s directory. This makes the process of modifications seamless.
Finally I need to create an HTTP handler to invoke the page. This was the part I was most worried about I suppose, but that’s actually fairly straight forward. For testing I just used an ASHX handler, but a real handler would be required to handle all of the pages:
<%@ WebHandler Language="C#" Class="Loader" %>
using System;
using System.Web;
public class Loader : IHttpHandler {
public void ProcessRequest (HttpContext context)
{
SubProject.DefaultASPX_PAGE Page = new SubProject.DefaultASPX_PAGE();
Page.ProcessRequest(context);
}
public bool IsReusable {
get
{
return false;
}
}
}
And voila – basic packaging… It works.
There are a few issues of course that need to be watched out for. If you do this you should take care to get all your images and CSS files (if needed) from embedded resources so you don’t end up having dependencies.
The HTTP Handler should be a regular (non-ASHX) handler should be configured for the special URLs you’d be handling probably with a set of page names or requests fired at a special directory most likely. I haven’t gone through and actually done this yet – I’ll wait till I’m done because I suspect that developing in this roundabout way is probably not as convenient as having the pages in a live project. <s>
The Voices of Reason
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
At least in theory...
Matt
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
I think a VirtualPathProvider might be a good idea in some cases. I haven't played with this enough yet to see if it will be necessary. I think at this point a handler reference with some sort of page prefix to identify the request should work (_LocalizationAdmin.aspx, _LocalizationResourceExport.aspx etc.)
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
However, you can (and that's what the example above does actually) builld a custom resource provider that stores the resources in a different store like a database in which case you can edit the resources at runtime and affect the running application.
I'll be posting more on this after ASP.NET Connections is over next week since I'm doing a talk on just this topic <s>
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
Sorry for commenting an old post. But I can't get this thing to work. When I run "Webhandler.ashx" in the browser i only get a blank output. Can't see the content of the page. What am I missing here?
With best regards,
/ Adrian
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
I'm attempting to follow the example in your post, and I've sepnt a good number of hours tinkering with different options to try to get it to work.
Unfortunately, my experience has been the same as Adrian's -- any attempt to capture the output/content of a page embedded in the WDP-compiled assembly does not work. Only a blank string is returned, but no exceptions are thrown.
HttpContext context = HttpContext.Current;
netfile.asp.css.content.DumbPage page = new netfile.asp.css.content.DumbPage();
page.ProcessRequest(context);Everything above works great until 'page.ProcessRequest()' is called. (i.e. my calling application can see the resource assembly just fine, and the 'page' variable is properly assigned. I have also confirmed the pages I'm attempting to load dynamically are directly callable from the WDP project itself (i.e. the pages are well-formed, etc.)
I have tried many different calling scenarios, including context.Server.Execute(), putting the code above into pages, generic handlers, etc.
Can you think of any obvious reason why this wouldn't work for me?
Best Regards,
David Montgomery
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
Any help will be appreciated, thank you in advance.
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
The error is "Object reference not set.." when I try to use any user control on page in code behind.
In my page I've literal control that I want init (in Page_Init) with text in code behind.
On those row the I receive a run time error.
Whant can be a problem?
Any help will be appreciated, thank you in advance.
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
ASP.DefaultASPX_PAGE Page = new ASP.DefaultASPX_PAGE();
Page.ProcessRequest(context);
/stefan
# re: Packaging ASP.NET ASPX Pages into a separate Assembly
You create a WAP with all your ASCX files and the code behind + a web deployment project and then you can distribute the User Controls just like a web control without having to have the ascx files.