ExtJS 和 .NET WebServices,远程域访问






4.82/5 (5投票s)
使用 ExtJS 远程访问 .NET Web 服务。
引言
在我的上一篇文章中,我展示了从 ExtJS JavaScript 库访问 .NET Web 服务是多么容易。这个解决方案有一个很大的缺点。由于安全原因,用于执行 AJAX 调用的 HTTPRequest
方法仅限于域内调用。如果我们的 Web 服务位于不同的机器和不同的域上怎么办?您将在本文中找到这个问题的答案。
解决方案
正如我之前提到的,使用 HTTPRequest
方法无法访问位于不同域中的数据,但我们可以使用一个小技巧。使用 JavaScript,可以向您当前的文档添加任何 HTML 标签 - 甚至是 SCRIPT
标签。众所周知,SCRIPT
标签允许将 JavaScript 代码包含到文档中,并且 SCRIPT
标签也可以有一个 JavaScript 代码所在的 URL。这不像 HTTPRequest
那样仅限于同一域。让我们想象一下,在这种情况下,我们的源代码是远程和动态生成的数据,作为有效的 JavaScript 代码返回。当文档准备就绪时,我们可以访问这些数据,仅此而已。这个解决方案有两个缺点。性能略差(我们需要调用远程域等),并且我们必须准备服务器端以处理 script-tag 请求。在 ExtJS 端,我们可以直接使用 ScriptTagProxy
对象类而不是常规的 HttpProxy
。
让我们从上一篇文章中获取数据
{ "d": [{"AgentID": 1, "FirstName": "Jelena",
"LastName": "Akerhus"},{"AgentID": 2,
"FirstName": "Londo", "LastName": "Molari"}]}
为了使其与 ExtJS ScriptTagProxy
类一起使用,我们需要以这种格式返回数据
stcCallback001({ "d": [{"AgentID": 1,
"FirstName": "Jelena", "LastName": "Akerhus"},
{"AgentID": 2, "FirstName": "Londo",
"LastName": "Molari"}]});
嘿,这看起来像是一个 JavaScript 函数调用,并以我们的数据作为参数提供吗?是的,完全正确!回调函数的名称由 ScriptTagProxy 类作为添加到 URL 的参数提供。此回调的默认名称是... callback。访问远程数据源的 URL 如下所示
http://your-remoted-domain/ScriptTagProxyHandler?callback=stcCallback001
ScriptTagProxy
将完成提取数据并将其放入存储区的工作。我们所需要做的就是指定 ScriptTagProxy
而不是 HttpProxy
。让我们从上一篇文章中获取代码并更改代理。
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']
});
现在我们需要弄清楚如何使我们的 Web 服务与 ScriptTagProxy
一起工作。可以使用名为 PageProxy 的解决方案轻松实现。什么是 PageProxy?简单来说,它是一个 ASPX 网页,它将接收所有请求,并使用反射,将它们转发到 Web 服务;然后它将取回响应,该响应是一个包含 JavaScript 回调函数的容器,并将其转发给请求的发送者。
首先,我们需要创建一个 ASPX 网页;我们将其命名为 ScriptPageProxy.aspx。为了与 Web 服务 GET 方法调用保持兼容性,我们希望使用在 URL 的最后一部分中指定的方法名称来调用 Web 服务,然后捕获在 Request
对象中发送的参数。
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 anything wrong happens,
// just return exception serialized to json
}
// Prepare and send back response
sb.AppendFormat("{0}({{ d: {1} }});", callback, result);
Response.Write(sb.ToString());
}
为了帮助完成此任务,有两个辅助方法。首先,我们使用其类型和方法名称调用 Web 服务方法。另一个只是任何 .NET 对象序列化为 JSON 格式。
/// <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;
// Get parameters directly from Request object
string paramValue = Request[paramName];
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);
}
当 ScriptPageProxy 页面准备就绪时,我们所需要知道的就是如何调用它。在 JsonStore
声明中,指定此页面的 URL。如果我们认为 www.remote.com 是我们的域,它将如下所示
var store = new Ext.data.JsonStore({
autoLoad: true,
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.remote.com/ScriptPageProxy.aspx/GetPeople',
}),
root: 'd',
id: 'Id',
fields: ['Id', 'FirstName', 'LastName', 'BirthDate']
});
如果您想向 Web 服务发送任何参数,您可以使用 GET 或 POST 方法发送它们,连同请求一起发送。例如,要发送一个名为 Category 且值为 Financial 的参数
var store = new Ext.data.JsonStore({
autoLoad: true,
proxy: new Ext.data.ScriptTagProxy({
url: 'http://www.remote.com/ScriptPageProxy.aspx/GetPeople',
}),
baseParams: { Category: 'Financial' },
root: 'd',
id: 'Id',
fields: ['Id', 'FirstName', 'LastName', 'BirthDate']
});
源代码
随附的源代码包含一个附加项目,允许您以非常简单的方式创建 ScriptPageProxy。您所需要做的就是创建一个新的 ASPX 页面,将父类更改为 ScriptPage
,并使用 ScriptPageAttribute
描述它以显示目标 Web 服务类是什么。所有内容都作为源代码提供,欢迎随时发送有关此类的任何问题和评论。