Possible to make this work together with 3rd party libs like Devexpress?

May 2, 2011 at 11:15 AM

Great library you've developed. Thanks a lot!

Having a project that uses Devexpress and Microsoft Ajax, there are lots of "WebResource.axd" and "ScriptResource.axd" files being used to send JavaScript.

Do you think, it is possible to use the steps outlined in "Configure Partially Xpedited Web Site" to also compress these AXD files? I tried to add multiple handlers of Xpedite.Handlers.JavaScriptMinificationHandler to the "web.config" file, but without any result.

(An example project would be this one, just view the HTML source)

Thanks
Uwe

Coordinator
May 2, 2011 at 2:23 PM

Hi,

Definitely possible. Xpedite is already setup to process "virtual" resources. The ResourceLoaderFactory checks to see if the resource requested is a physical or virtual resource and either pulls the file from disk or via a web request. The AXD file would be processed as a web request, however I believe that the existing WebResource/ScriptResource HTTP handler will conflict with Xpedite. So you were on the right path, I will have to give it some thought on how to ensure that it gets routed to Xpedite first (handler ordering in config file) and then Xpedite will have to be extended to support transfering to other handlers via Server.Transfer most likely. Work is still a little busy this week, but this should be a relatively small enhancement so I hope to get to it pretty quickly.

Chris

May 2, 2011 at 2:28 PM

Thanks a lot, Chris

If I can contribute and/or test anything, please let me know!

Cheers
Uwe 

Coordinator
May 8, 2011 at 7:19 PM
Edited May 8, 2011 at 7:21 PM

Hi,

Took a little longer to follow-up than expected; turned out to be a fairly busy week at work. I have been investigating options to make this work. Unfortunately, the good folks at Microsoft have made this a rather challenging problem (at least if you want to keep the code clean).

I had intentionaly overlooked this feature in the first version of Xpedite (http://xpedite.codeplex.com/wikipage?title=Compressor%20%28Content%20Compressor%20Module%29&referringTitle=Documentation) because of the fact that Reponse.Filter does not behave as expected when the request is handled by the AssemblyresourceLoader.

I am still looking in to my options, but some details on why this is a challenge below.


 Specicially, the problem is two fold:

1) The AssemblyResourceLoader writes directly to the Response.OutputStream as follows

Stream outputStream = context.Response.OutputStream;
int count = 1;

while (count > 0)
{
  count = manifestResourceStream.Read(buffer, 0, 0x400);
  outputStream.Write(buffer, 0, count);
}
outputStream.Flush();

This bypasses the registered response filters.

2) To make matters worse, the good MS folks call

context.Response.IgnoreFurtherWrites();

 

 That prevents all further actions on the response output (i.e., closing off the compression stream properly). 


Options being investigated:

 

 1) Delegating off to a new HttpRequest to retrieve the resource and then cache the response.

Pros: Simple & easy to implement

 Cons: Requires extra HttpRequest if result not found in the cache (not ideal).

2) Re-implement a portion of the AssemblyResourceLoader as seen here -> http://mironabramson.com/blog/post/2007/10/New--Shiny--WebResourceaxd-compression-Module.aspx

Pros: It works?

Cons: Seems like a kludge to me, and not really sure I want that code in Xpedite.

3) Reflection to undo Microsoft's work.

    public void OnPostRequestHandlerExecute(object sender, EventArgs e)
    {
      var httpHandler = HttpContext.Current.CurrentHandler;

      if (!(httpHandler is AssemblyResourceLoader))
        return;

      var response = HttpContext.Current.Response;
      var httpWriterField = typeof(HttpResponse).GetField("_httpWriter", BindingFlags.NonPublic | BindingFlags.Instance);
     
      if(httpWriterField == null)
        return;

      var ignoringFurtherWritesField = typeof(HttpWriter).GetField("_ignoringFurtherWrites", BindingFlags.NonPublic | BindingFlags.Instance);
      if(ignoringFurtherWritesField == null)
        return;

      var httpWriter = httpWriterField.GetValue(response);
      if (httpWriter == null)
        return;

      ignoringFurtherWritesField.SetValue(httpWriter, false);
    }

Pros: Slightly (barely) less hacky than 2

Cons: Relies on internal implementation of HttpResponse and HtmlTextWriter.

 

4) Delegate the existing AssemblyResourceLoader off to a SimpleHttpWorkerRequest to capture the output prior to sending back to the client.

Pros: Works within the confines of the existing framework without extra request or hackish solution.

Cons: Don't quite have it working yet.


May 8, 2011 at 7:42 PM

Thanks, Chris

Sounds like quite a bit of work; if you have ever some free time and will to do, I'll be more than happy if you implement these features.

Seems like a very good alternative to Aptimize which I would love to try out/buy, if I could only afford.

Best regards
Uwe