Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Packaging ASP.NET ASPX Pages into a separate Assembly


:P
On this page:

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:

 

  1. Created a new Web Application Project (I suppose a regular project would also work)
  2. Added a new page to it
  3. Compiled the project made sure it works and runs
  4. Created a Web Deployment Project for the WAP project
  5. Set options for a single Merge assembly, and not updateable (ie. Precompiled ASPX code)
  6. Added a Post build step to copy the two DLLs for the project to the Bin directory of the main
  7. 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


 

Tony Bunce
October 19, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

on a side note you can use the same method to make a library of User Controls act like web controls.

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.

Matt Ellis
October 20, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Nice! How about a Virtual Path Provider - it can intercept the request for the .aspx files and return them from a resource in your http handler project. The http handler project itself could contain the compiled codebehind classes and also the registration logic for the path provider.

At least in theory...

Matt

Rick Strahl
October 21, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Matt, you wouldn't need to load anything from a resource since WAP/WDP has the ASPX compiled already. The class exists and everything is ready to execute.

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.)

Matt Ellis
October 21, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Yeah, I'm a big fan of WAP + WDP. The nice part of this idea (if it works) is that you could deploy just one dll, rather than the code behind dll + the compiled page dll. I've been meaning to have a proper look at virtual path providers for a while.

Rick Strahl
October 21, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

I suppose for this 'template page' project you could use a standard Web project with WDP. That would allow compiling into a single DLL as well.

Murali
November 02, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

That project is interesting. I am interested to know how could i allow users to edit the resource strings stored in a compiled format. I would really appreciate more information and some light in this matter at my mail murai@hrdpower.com. Thx

Rick Strahl
November 02, 2006

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

You can't edit compiled resources.

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>

A Continuous Learner's Weblog
December 01, 2006

# A Continuous Learner's Weblog: October 2006


Adrian
March 16, 2007

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Hello,

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

David Montgomery
March 23, 2007

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Hi Rick,

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

ASP.NET Forums
July 11, 2007

# Entire page in assembly - ASP.NET Forums


Alex belik
April 22, 2009

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Hi, Rick, I'd found a problem with the special functionality (documents printing, realized as separate web application) to be shared within different corporate web applications. The solution proposed seems to me more then reasonable. But.. after numerous attempts to follow your steps, I can't realize how the components of the compiled dll can be visible in the target site? Did you added it as referenced? Or something else? I put it in the Bin folder, I added the reference to this dll in the target project, but still can't see it as described in your post (SubProject.DefaultASPX_PAGE Page = new SubProject.DefaultASPX_PAGE();).
Any help will be appreciated, thank you in advance.

Psy After
March 18, 2010

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

It's nice tutorial, but I've exception when executing end point Page (in example is SubProject.DefaultASPX_PAGE).
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.

Stefan Carlsson
September 03, 2010

# re: Packaging ASP.NET ASPX Pages into a separate Assembly

Use the ASP-namespace instead;

ASP.DefaultASPX_PAGE Page = new ASP.DefaultASPX_PAGE();
Page.ProcessRequest(context);

/stefan

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024