9

My web application (http://www.something.com/social/competition/) is currently requesting the WebResource.axd file like this:

<script src="/WebResource.axd?d=xxx" type="text/javascript"></script>

As we're using urlrewiting in a Netscaler to forward all requests for the "/social" folder onto a seperate server farm containing this app, the "/" root path won't resolve correctly as it will be requesting the resource from the something.com app.

Therefore I need to change the url of the requested script to either request it explicitly:

<script src="/social/WebResource.axd?d=xxx" type="text/javascript"></script>

or to request it using a relative path:

<script src="WebResource.axd?d=xxx" type="text/javascript"></script>

So far I've looked at overriding the render method, using a control adapter and various other things but haven't really got anywhere as of yet. Help please.

James Law
  • 6,067
  • 4
  • 36
  • 49

1 Answers1

11

Right, so it turns out after extensive research that it's practically impossible to override the rendering process for these files. So the only other option was a filthy, dirty, horrible hack!

protected void Page_Load(object sender, EventArgs e)
    {
        //Initialises my dirty hack to remove the leading slash from all web reference files.
        Response.Filter = new WebResourceResponseFilter(Response.Filter);
    }

public class WebResourceResponseFilter : Stream
{
    private Stream baseStream;

    public WebResourceResponseFilter(Stream responseStream)
    {
        if (responseStream == null)
            throw new ArgumentNullException("ResponseStream");
        baseStream = responseStream;
    }

    public override bool CanRead
    {
        get { return baseStream.CanRead; }
    }

    public override bool CanSeek
    {
        get { return baseStream.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return baseStream.CanWrite; }
    }

    public override void Flush()
    {
        baseStream.Flush();
    }

    public override long Length
    {
        get { return baseStream.Length; }
    }

    public override long Position
    {
        get
        {
            return baseStream.Position;
        }
        set
        {
            baseStream.Position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return baseStream.Read(buffer, offset, count);
    }

    public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
        return baseStream.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        baseStream.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        //Get text from response stream.
        string originalText = System.Text.Encoding.UTF8.GetString(buffer, offset, count);

        //Alter the text.
        originalText = originalText.Replace("/WebResource.axd", "WebResource.axd");
        //Write the altered text to the response stream.
        buffer = System.Text.Encoding.UTF8.GetBytes(originalText);
        this.baseStream.Write(buffer, 0, buffer.Length);

    }

This intercepts the stream to the page and replaces all occurrences of "/WebResource.axd" with "WebResource.axd". As it's a relative path it resolves beautifully!

Another solution occurred to me which required installing the web application to a virtual directory which mimicked the "/social" keyword redirect. This would cause asp.net to update the HttpRuntime.AppDomainAppVirtualPath to include the "/social" in the references on the page and would therefore resolve correctly.

Big whoop whoop!

James Law
  • 6,067
  • 4
  • 36
  • 49
  • 2
    originalText = originalText.Replace(HttpContext.Current.Request.ApplicationPath+"/", VirtualPathUtility.MakeRelative(HttpContext.Current.Request.Url.AbsolutePath, "~/")); this line will make all absolute links relative links, obtaining the right ../ elements. – Emanuele Greco Oct 04 '11 at 16:26
  • I read the question, tried and used this code -and voted up-. It's just a general suggestion to improve the code posted for general cases. – Emanuele Greco Oct 12 '11 at 12:24
  • That doesn't work in this case as the application doesn't know about the "/social" path because of the content switching. – James Law Dec 04 '11 at 03:28
  • @JamesLaw - I am also facing the same problem, I am not able to understand your second suggestion regarding mimicking "/social" keyword. Currently we have a load balancer which makes a request to our site. so the url of the site becomes root + host name, we are using reportviewer control which automatically makes a call to the webresource.axd to load controls. can you please suggest something on the same. – Punit Jul 04 '13 at 06:39
  • 2
    @Punit you need to create a virtual application within IIS and host your code there. For example, in my case I'd create the virtual application "social" off my root website which points to the application, ergo making http://localhost/social/ behave as the application root. – James Law Jul 04 '13 at 07:47
  • I thought this would be my magic bullet until I ran into problems with pages utilizing asynchronous postback. In this situation, a specially formatted response is crafted server-side that includes values for the size of a section. That size gets sent before content, so it's difficult to catch and change. Since you're removing a character, the size definitely changes. See https://weblogs.asp.net/leftslipper/sys-webforms-pagerequestmanagerparsererrorexception-what-it-is-and-how-to-avoid-it – Greg Vogel Apr 08 '21 at 19:38