Introduction


In last article I showed how easy is access to .NET WebService from ExtJS JavaScript Library. This solution has one big disadvantage. Due to security reasons HTTPRequest method used for performing AJAX calls is restricted to in-domain calls only. What in the case if our WebService is located on different machine and different domain? You will find answer for this question in this article.


Solution


As I mentioned before it impossible to access data located in different domain using HTTPRequest method, but we can use some trick. It is possible, using JavaScript to add any html tag to current document - even SCRIPT tag. As all we know SCRIPT tag allows to include JavaScript code into document and also SCRIPT tag can have URL where JavaScript code is located. This is not limited to the same domain, like in HTTPRequest case. Let's imagine that our source code in this case is remotelly and dynamically produced data returned as valid JavaScript code. When document is ready, we can acces this data and that's all. There 2 drawbacks of this solution. Performace is slightly worse (we need to call some remote domain, etc) and we have to prepare server side to handle script-tag requests. On ExtJS side we can just use ScriptTagProxy object class instead of regular HttpProxy.


Let's take data from last article:



{ "d": [{"AgentID": 1, "FirstName": "Jelena", "LastName": "Akerhus"},{"AgentID": 2, "FirstName": "Londo", "LastName": "Molari"}]}

To make it to work with ExtJS ScriptTagProxy class we need to return data in format like this:



stcCallback001({ "d": [{"AgentID": 1, "FirstName": "Jelena", "LastName": "Akerhus"},{"AgentID": 2, "FirstName": "Londo", "LastName": "Molari"}]});

Hey, does it look like JavaScript function call with our data provided as parameter? Yes exactly! Name for callback function is provided by ScriptTagProxy class as parameter added to URL. Default name for this callback is... callback. URL to acces remote data source will look like this:


http://your-remoted-domain/ScriptTagProxyHandler?callback=stcCallback001


ScriptTagProxy will do the job to extract data and put it into the store. All we need is to specify ScriptTagProxy instead of HttpProxy. Let's take code from last article and change proxy.



var store = new Ext.data.JsonStore({
autoLoad: true,
proxy: new Ext.data.ScriptTagProxy({
url: 'http://your-remote-domain/ScriptTagProxyHandler',
}),
root: 'd',
id: 'Id',
fields: ['Id', 'FirstName', 'LastName', 'BirthDate']
});

Now we need figure out how can we make our web service work with ScriptTagProxy. It could be easilly achieved with solution called PageProxy. What is PageProxy? In simple words: this is an aspx web page wich will receive all requests, and using reflection forward them to web service, then it will get back the response, enclousure with javascript callback function and forward it to request's sender.


Create aspx page and put this code there:



public partial class SimpleScriptPageProxy : Page
{
protected void Page_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
string result = "";
string callback = "";

try
{
// Get method name in web service GET call format
string methodName = Request.PathInfo.Replace("/", "");
// Get name of callback function
callback = Request["callback"].ToString();

// Invoke web service method and serialize response to json
// !Important!: Service is type of our web service
result = jsonSerialize(invokeMethod(typeof(Service), methodName));
}
catch (Exception ex)
{
result = jsonSerialize(ex); // When somethig wrong happens, just return exception serialized to json
}
// Prepare and send back response
sb.AppendFormat("{0}({{ d: {1} }});", callback, result);
Response.Write(sb.ToString());

}

/// <summary>
/// This method invokes fn method on type Type and returns answer.
/// </summary>
/// <param name="type">Type of class with method</param>
/// <param name="fn">Function name</param>
/// <returns>Method result</returns>
private object invokeMethod(Type type, string fn)
{
object result;
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod(fn);
ParameterInfo[] parameters = method.GetParameters();

if (parameters.Length == 0)
{
result = method.Invoke(instance, null);
}
else
{
List<string> paramValues = new List<string>();
for (int i = 0; parameters.Length > i; i++)
{
string paramName = parameters[i].Name;
string paramValue = Request[paramName]; // Get parameters directly from Request object

paramValues.Add(paramValue);
}
result = method.Invoke(instance, paramValues.ToArray());
}
return result;
}

// Helper method for json serialization
private string jsonSerialize(object o)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(o);
}
}

Set url to this web page in ScriptTagProxy and that's all. If You like to send any parameters to web service You can send them with request using GET or POST methods.

4 comments:

Hi Rafal,
this post is very interesting. I get your example code to try to use ScriptTagProxy.

I'd like to pass a parameter to the ASPX page in POST using ScriptTagProxy but I wasn't be able to do it.

How I can pass parameters via POST to the ASPX page using the ScriptTagProxy ?

Can you show me an example?

Hope you can help me.

Thanks
Brun

September 15, 2010  

Hi Brun,

Unfortunatelly while using ScriptTagProxy You are not able to send POST data. It is because ExtJS in uses SCRIPT html tag to go out of webpage sandbox. So I am afraid the only option is to use GET http method.

Hope it helps!

Take care,
Rafal

September 15, 2010  

HI Rafal,

I am trying to return xmldocument from a aspx page to a Ext.dat.XmlReader object. Response.write returns only string (ex. json string). How can we return a xmldocument object? how can we call a webmethod returning xmldocument within a aspx page from extjs? Please advise.

Thanks,
Valar

October 22, 2010  

@Valar sorry to say, but lately I am little bit out of ExtJS & ASP.NET subjects, but you may looking for XmlSerializer:

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

November 27, 2010  

Newer Post Older Post Home