ASP.NET Proxy Page – Used for Cross Domain Requests from AJAX and JavaScript

One of the pain points with developing AJAX, JavaScript, JQuery, and other client-side behaviors is that JavaScript doesn’t allow for cross domain request for pulling content. For example, JavaScript code on www.sharepointjohn.com could not pull content or data from www.bing.com.

One way to overcome this issue is by using a server-side proxy on the site running the JavaScript code. There is already are well documented PHP solutions on the web, however I couldn’t find very many .NET-based solutions. This simple C# code takes the URL passed to it through the URL encoded query string, retrieves the content of the URL and outputs it as if it were content on the site.

Proxy.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net;
using System.IO;

namespace Proxy
{
    public partial class _Proxy : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string proxyURL = string.Empty;
            try
            {
                proxyURL = HttpUtility.UrlDecode(Request.QueryString["u"].ToString());
            }
            catch { }

            if (proxyURL != string.Empty)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(proxyURL);
                request.Method = "GET";
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                if (response.StatusCode.ToString().ToLower() == "ok")
                {
                    string contentType = response.ContentType;
                    Stream content = response.GetResponseStream();
                    StreamReader contentReader = new StreamReader(content);
                    Response.ContentType = contentType;
                    Response.Write(contentReader.ReadToEnd());
                }
            }
        }
    }
}
Proxy.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Proxy.aspx.cs" Inherits="Proxy._Proxy" %>

The Proxy.aspx page is simply blank except for the Page tag. When passing the URL to the query string, it is important that it is URL encoded. This helps to prevent query strings of the remote site URL from interfering with the Proxy page.

Example Usage
http://www.yoursite.com/proxy.aspx?u=http%3a%2f%2fwww.google.com

ASP.NET Proxy Page Source

Happy coding!

John Chapman

Hello, I'm John Chapman. I am a SharePoint Developer for Sitrion (formerly NewsGator) living in Denver, Colorado. I develop solutions using SharePoint and .NET, and I thrive on the challenge of writing code to overcome the impossible, annoying, or otherwise difficult obstacles.

More Posts - Website - Twitter - LinkedIn - Google Plus

  • http://jasonkuter.com Jaosn Kuter

    Brilliantly simple solution, thanks! This will work wonders on our SharePoint intranet.

    • http://www.sharepointjohn.com John Chapman

      That is exactly what I use this for. I place the page in the LAYOUTS folder on the server to make it available to all the SP sites. I primarily use it for consuming RSS feeds across domains.

  • http://www.i8dm.com Kevon K. Hayes

    Well done. Good to see what’s possible.

  • Michael H

    But it doesn’t support POST.

    • http://www.sharepointjohn.com John Chapman

      In what scenario would you want to POST to this proxy page?

      • Karl

        In case you are using a REST based service and don’t want to use the ugly GET? :-)

        • Peter Neil

          Your REST based service is very RESTful if it isn’t using GET for READING DATA.

          I can see that using a POST might be desirable to post to another server and make sure the Proxy follows any redirects for you.

  • Andy R

    After seeing this, http://www.experts-exchange.com/Q_26452332.htm, I can think of several situations where you might want to “POST” data to a remote web-service, and stick the results in a local page e.g.
    * Exchange rate conversion,
    * Stock price lookup,
    * delivery rate lookup.
    Personally I’d use Apache to Reverse Proxy the requests to the remote site, by adding the entries below to the httpd.conf, but there are plenty of equivalents for IIS, out there e.g. http://www.codeproject.com/KB/web-security/HTTPReverseProxy.aspx

    #— cut ‘n’ paste into you Apache httpd.conf —
    ProxyRequests Off

    Order deny,allow
    Allow from all

    ProxyPass /proxy http://www.some.webservice
    ProxyPassReverse /proxy http://www.some.webservice
    #—- Cut ends —

  • http://www.kitchencarts360.com Romona

    It is great to see what is possible!

  • Nico Witteman

    Lovely and simple.

    I would very much to use this to set the src-attribute for an img, but it does not seem to work. Any ideas?

    • http://www.sharepointjohn.com John Chapman

      Can you explain the scenario a bit more? I’m not sure I see a correlation between this proxy solution to populating the src for an image.

      • Dan

        John,

        I also have the requiremnt to proxy the SRC attribute of an image. The scenario is that a page reads the contents of an RSS feed (not my own) which resides on a different domain. The description tag of the RSS feed contains HTML mark-up included within it including an image.

        The image doesn’t currently display which i believe is due to the cross domain requests restriction. I would like to deliver the contents of the image via a proxy page in a similar to which you have described. I have based my attempt on your example provided but have been unable to get it to work.

  • Matthew Henry

    You also need to copy the user-agent
    request.UserAgent = Request.UserAgent;

  • Fabio

    Hi!
    Thanks for the solution.
    I’m trying to use it for all requests (JS, Images, XML).
    Unfortunately it’s not working…For example, I’m trying to get an image using the proxy, so I use the following URL

    persacore.aspx?u=imagens/icones/tema_1/m/energia_m.png

    but the browser does not recognize it as an image. The Content Type is correct. Any ideas?

  • Tom C

    This is great thanks for sharing. With minor changes (accessing the Request object through context) I put this in an asynchronous HTTP handler for added efficiency and to support concurrency. I also updated a few things to support POST requests, as I do think this is worthwhile

    • Bob

      Did you publish your modified code anywhere? What you added sounds exactly like what I thought was missing from this great post.

  • Pingback: [SharePoint 2010] Cross-Domain Proxy Page for Client-Side Scripts « SharePoint John – John Chapman's Blog About SharePoint, ASP.NET, C#, jQuery, SQL

  • TimTim

    Thanks this proxy works great, except for images. Any image that is requested will not show in a browser due to “The image … cannot be displayed because it contains errors.” If I request an image and then request it via the proxy the first request returns fine and the 2nd returns this error message. Any suggestions? In case you are wondering I do have a valid case for requesting images – I’m performance testing mapping services via ajax

  • http://www.sharepoint.inf4web.com SharePoint Cheshire

    Thanks for simple solution! This is working great for me :)

  • Daniel

    How would we use this in a SharePoint site? I added a page which resides in layouts and all I get an an error with no reason.

  • Ichraf Tounsi

    Hi John,

    i have problem when i try to create a web service in C#.Net and call its webMethod with javaScript in .html file that is located on my desktop, the problem is when i tried to run it throw my IE webbrowser, it works with no issues, but on firefox and google chrome, the xhr.status = 0 and xhr.responseXML.xml is null,

    here is my html code :

    Premiere Application

    function resultat(){

    “use strict”;

    // alert(’1′);

    var strRequest ;

    var xhr ;

    if(window.XMLHttpRequest) {

    try {

    xhr = new XMLHttpRequest();

    } catch(e) {

    xhr = false;

    }

    } else if(window.ActiveXObject) {

    try {

    xhr = new ActiveXObject(“Msxml2.XMLHTTP”);

    } catch(e) {

    try {

    xhr = new ActiveXObject(“Microsoft.XMLHTTP”);

    } catch(e) {

    xhr = false;

    }

    }

    }

    xhr.open (“POST”, “http://localhost/TemperatureWebService/Convert.asmx”,

    true);

    xhr.setRequestHeader( “Content-Type”,”text/xml; charset=utf-8″);

    xhr.setRequestHeader(

    “SOAPAction”, “http://tempuri.org/CelsiusToFahrenheit”);

    // alert(’3′);

    strRequest = “”;

    strRequest = strRequest + “”;

    strRequest = strRequest + ” “;

    strRequest = strRequest + “100″;

    strRequest = strRequest + “”;

    strRequest = strRequest + “”;

    // alert(strRequest);

    xhr.onreadystatechange = function () {

    // alert(xhr.readyState);

    // alert(xhr.status);

    if(xhr.readyState === 4 && (xhr.status === 200 || xhr.status === 0)){

    //receiving response

    }

    };

    xhr.send(strRequest);

    alert(‘result !’);

    try

    {

    alert(xhr.responseXML.xml);

    document.getElementById(“h”).innerHTML=xhr.responseXML.xml;

    }

    catch(e) {

    // xhr = false;

    }

    }

    Application :

    wait

    hi

    ———————————

    and here is my web service : convert.asmx :

    using System;

    using System.Collections;

    using System.Linq;

    using System.Web;

    using System.Web.Services;

    using System.Web.Services.Protocols;

    using System.Xml.Linq;

    ///

    /// Description résumée de Convert

    ///

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    // Pour autoriser l’appel de ce service Web depuis un script à l’aide d’ASP.NET AJAX, supprimez les marques de commentaire de la ligne suivante.

    [System.Web.Script.Services.ScriptService]

    public class Convert : System.Web.Services.WebService {

    public Convert () {

    //Supprimez les marques de commentaire dans la ligne suivante si vous utilisez des composants conçus

    //InitializeComponent();

    }

    [WebMethod]

    public string HelloWorld() {

    return “Hello World”;

    }

    [System.Web.Services.WebMethod()]

    public double FahrenheitToCelsius(double Fahrenheit)

    {

    return ((Fahrenheit – 32) * 5) / 9;

    }

    [System.Web.Services.WebMethod()]

    public double CelsiusToFahrenheit(double Celsius)

    {

    return ((Celsius * 9) / 5) + 32;

    }

    }

    ———————————-

    please help me, i think it is an issue of cross domain.. i tried several methods but in vain..

  • Marc

    Hi John,
    Is there any way to make this compatible with post requests as well? Also how would I integrate this solution into an MVC 4 web application?