65.9K
CodeProject 正在变化。 阅读更多。
Home

ExtJS 和 .NET WebServices,远程域访问

2009年7月13日

CPOL

3分钟阅读

viewsIcon

44159

downloadIcon

630

使用 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 服务类是什么。所有内容都作为源代码提供,欢迎随时发送有关此类的任何问题和评论。

© . All rights reserved.