从 Silverlight 应用程序访问 Web 服务
本文讨论了如何从 Silverlight 应用程序访问 Web 服务。文中附有示例代码。
引言
在本文中,我们将了解如何从 Silverlight 应用程序访问 Web 服务。
涵盖的主题
- 使服务能够跨域边界访问
- “clientaccesspolicy.xml” 文件和 “crossdomain.xml” 文件在安全性和最佳实践方面的意义。
- 使用 crossdomain.xml 文件允许跨域访问
- 使用 clientaccesspolicy.xml 文件允许跨域访问
- 使用 Web 开发者助手工具
首先,我们将使用 Visual Studio 创建一个 Web 服务。然后,我们将使用另一个 Visual Studio 实例创建一个 Silverlight 应用程序。在此 Silverlight 应用程序中,我们将引用 Web 服务并使用该 Web 服务公开的方法。我们将了解如何使用 “crossdomain.xml" 和 “clientaccesspolicy.xml” 文件,以便能够从 Silverlight 应用程序调用 Web 服务方法。
第一步:使用 Visual Studio 创建 Web 服务
打开 Microsoft Visual Studio 2010 -> 文件 -> 新建网站 -> 在已安装模板下选择“Visual C#” -> 选择 ASP.NET 空网站,并将其命名为 “MyWebApplication
”,如下图所示。

第二步:打开解决方案资源管理器(视图 -> 解决方案资源管理器)。右键单击粗体的“MyWebApplication
”,然后单击“添加新项”-> 选择 Web 服务(向下滚动以查看 Web 服务)并将其重命名为 MyWebService.asmx”,如下图所示。然后单击“添加”。

将 Web 服务添加到应用程序后,打开 “MyWebService.asmx.cs” 文件,您会发现此 Web 服务公开了 “HelloWorld
” 方法,Silverlight 客户端应用程序可以调用该方法。现在,构建 Web 服务并按 Ctrl+F5 运行应用程序。为了简单起见,我没有添加其他方法,而是使用了现有的 “HelloWorld
” 方法。

这将打开带有 webservice 的浏览器窗口,如上所示。正如我们所见,“MyWebService
” webservice
公开了 HelloWorld
方法。从浏览器复制 Web 服务 URL。
”https://:1133/MyWebService.asmx”
这是包含以下内容的 webservice URL:
- 访问 webservice 所使用的协议(http)。
- 托管
webservice
的服务器。由于我们使用 Visual Studio 开发服务器在本地计算机上开发了 web 服务,因此它托管在端口号为 1133 的 localhost 上。它可以是托管webservice
的任何服务器名称/端口号。web 服务 “MyWebService.asmx”。Web 服务具有扩展名 “.asmx”。 - 我们将在 Silverlight 应用程序中使用此
webservice
URL。
第三步:现在创建一个 Silverlight 应用程序。
打开一个新的 Visual Studio 实例 -> 文件 -> 新建项目 -> 在已安装模板下方 -> 选择 Visual C# -> Silverlight -> Silverlight 应用程序 -> 将其重命名为 “MySilverlightApplication
”,如下图所示,然后单击“确定”按钮。

这将创建一个 “MySilverlightApplication
” Silverlight 应用程序。让我们添加一个 web 服务引用:打开解决方案资源管理器(视图 -> 解决方案资源管理器)-> 右键单击 “MySilverlightApplication
” -> 单击。

添加服务引用 -> 这将打开“添加服务引用”窗口。在地址框中粘贴我们之前复制的 web 服务 URL:https://:1133/MyWebService.asmx -> 转到。这将发现 web 服务并将其添加到“服务”列。现在单击“确定”。这会将 web 服务添加到项目并生成代理类,以便我们可以从 Silverlight 应用程序访问 web 服务方法。在“服务引用”文件夹中,您将找到 “MyServiceReference
” 文件,这是我们添加了引用的 webservice
。它还会生成 “ServiceReferences.ClientConfig
” 文件,其中包含有关 web 服务的详细信息,例如 Web 服务位置(地址)、绑定和其他详细信息。您可以通过右键单击“MyServiceReference
”并选择“在对象浏览器中查看”来探索“服务引用”文件夹中的 MyServiceReference
文件。请注意,它包含 MySilverlightApplication.MyServiceReference.MyWebServiceSoapClient
类及其方法。这些是调用服务的方法。
注意:如果 Web 服务是使用 Visual Studio 开发服务器开发的,请确保 Web 服务正在运行。

第四步:通过构建服务的代理,从 Silverlight 应用程序调用 webservice
方法。
在 MainPage.xaml 文件中添加一个 TextBlock
,如下所示。
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,10,0,0"
Name="textBlock1" Text="TextBlock" VerticalAlignment="Top" />
</Grid>
在客户端应用程序的 MainPage.xaml.cs(代码隐藏)文件中,在页面顶部添加以下 using
语句。
using MySilverlightApplication.MyServiceReference;
在使用服务之前,您必须实例化 Web 服务代理。
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//instantiate the Web service proxy
MyWebServiceSoapClient proxy = new MyWebServiceSoapClient();
//Invoke the "HelloWorldCompleted" method when the
//"HelloWorld" method is executed and returns.
proxy.HelloWorldCompleted +=
new EventHandler<HelloWorldCompletedEventArgs>(proxy_HelloWorldCompleted);
//Call the "HelloWorld" method.
proxy.HelloWorldAsync();
}
//Invoked when the "HelloWorld" method is executed and returns
void proxy_HelloWorldCompleted(object sender, HelloWorldCompletedEventArgs e)
{
if (e.Error == null)
{
textBlock1.Text = e.Result.ToString();
}
else
{
textBlock1.Text = "Error getting the result";
}
}
}
这里需要注意的几点是:
- Silverlight 中的所有 Web 服务调用都是异步的。
- Web 服务代理包含每个服务操作的两个成员:一个异步方法和一个完成事件。例如,考虑 “
HelloWorld
” 服务操作。我们首先在MainPage()
构造函数的作用域内将一个EventHandler
添加到HelloWorldCompleted
。这是当服务返回我们请求的数据时将被调用的事件。设置完事件后,我们就可以通过调用HelloWorldAsync
方法来调用服务了。上面的示例显示了这两个步骤的代码。 - Visual Studio 可以轻松编写异步代码。只需键入
proxy.HelloWorldCompleted
+=,然后按两次 TAB 键。事件处理程序和事件处理方法将自动创建。 - 事件处理程序指定当服务返回某些数据时应调用
proxy_HelloWorldCompleted
方法。 - 我们需要在 “
proxy_HelloWorldCompleted
” 方法中妥善处理错误。为了处理错误情况,在访问Result
属性之前,必须通过检查结果事件参数上的Error
属性来检测错误。如果您尝试在发生错误条件时访问Result
属性,将会引发异常。上面的示例显示了如何使事件处理程序能够抵御错误。 - 错误可能由多种原因引起,例如:服务可能不可用,或者服务地址可能错误,或者也可能由于跨域访问问题而发生错误。
第五步:现在按 Ctrl+F5 运行项目。糟糕。应用程序会报错。为了确切地看到错误所在,我使用了“Web 开发者助手”工具。这个工具是 Internet Explorer 的一个免费浏览器扩展,它为 Web 开发者、Ajax 和 ASP.NET 开发者提供了一套工具和实用程序。该工具提供了 DOM 查看器、HTTP 跟踪工具、脚本诊断和即时窗口等功能。
您可以从 “http://projects.nikhilk.net/WebDevHelper” 网站下载并安装“Web 开发者助手”工具。
要在 IE 窗口中打开 Web 开发助手工具 -> 右侧转到工具 -> 浏览器栏 -> 单击 Web 开发者助手。然后刷新页面,并选中“启用日志”复选框。您将看到 Silverlight 首先查找 Silverlight 的策略定义文件:“clientaccesspolicy.xml”。如果找不到,它会搜索“crossdomain.xml”文件。在本例中,它找不到这两个文件,因此返回的状态码是“404”。

这意味着我们必须添加这些文件才能向 webservice
发出服务请求。Web 服务作者有责任在服务器上放置跨域策略文件,以允许从应用程序跨域访问其服务。
第六步:现在,将一个 “xml” 文件添加到 webservice “MyWebApplication
” 中,内容如下,并将其命名为 clientaccesspolicy.xml,它允许访问服务。以下配置允许任何其他域访问当前域上的所有资源。
<?xml version="1.0" encoding="utf-8" ? >
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain url="*"></domain>
</allow-from>
<grant-to>
<resource include-subpaths="true" path="/"></resource>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
或者,如果您只想允许从一个其他域访问,例如 http://microsoft.com,请将 clientaccesspolicy.xml 文件中 <allow-from>
元素内的 <domain uri="*"/>
行替换为 <domain uri="http://microsoft.com"/>
。
要允许从通过 HTTP 应用程序托管的任何 Silverlight 控件访问 HTTPS 服务,您需要在 <allow-from>
元素内放置 <domain uri=”http://*” />
元素。访问域。
注意:确保这两个文件:“crossdomain.xml” 和 “clientaccesspolicy.xml” 位于 web 服务应用程序的根目录下。
您还可以通过添加具有以下配置的 XML 文件来添加 “crossdomain.xml” 文件。
<?xml version="1.0" encoding="utf-8" ?>
<!-- The file must be configured to allow access to the service from any other domain,
or it is not recognized by Silverlight 4.
Save the crossdomain.xml file to the root of the domain where the service is hosted.
If, for example, the service is hosted in http://fabrikam.com,
then the file must be located at http://fabrikam.com/crossdomain.xml.
-->
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
</cross-domain-policy>
第七步:现在运行 Silverlight 应用程序(Ctrl + F5)。它会成功执行,您可以在“Web 开发者工具”中看到对策略文件的调用没有任何错误,因为状态码是 200。

下面列出了一些使用跨域策略文件的实际示例:
访问 http://www.amazon.com/crossdomain.xml,您会发现以下文件。它不允许公开访问,但允许从不同网站访问。

另一个例子是 flickr 网站。它提供了与他们自己的网站不同的跨域访问。即 api.flickr.com/crossdomain.xml。
它允许使用一些可控机制进行 API 访问,将服务保留在不同于内容域的域上。这是使用 crossdomain 文件时要遵循的最佳实践之一。
以下是一些有关跨域访问的最佳实践:
当公开用于跨域访问的服务时,请遵守以下注意事项:
在启用了跨域的服务中,仅依赖消息正文来验证调用者。
例如,假设一个启用了跨域的照片共享服务,该服务需要用户身份验证,并且使用 http://api.picasa.com/PhotoService/GetPhotoalbum 进行访问。该服务不应依赖 Cookie 来验证用户。但是,可以使用一种身份验证方案,其中用户身份验证令牌作为消息或 URL 的一部分传递 - 例如,http://api.picasa.com/PhotoService/GetPhotoalbum?userToken=ABCOLK。
将启用了跨域的服务与常规 Web 页面和未启用跨域的服务分开。在使用 Silverlight 策略文件:clientaccesspolicy.xml 文件时,最好通过域或子域进行此分隔。可以通过 URL 空间进行分隔。
例如,http://flickr.com 是一个 Web 站点,其 Web 页面使用不安全的跨域身份验证机制(如 Cookie)。要添加对跨域访问安全的服务,请将其添加到单独的子域,如 http://api.flickr.com。然后 http://flickr.com/clientaccesspolicy.xml 应该不存在,但 http://api.flickr.com/clientaccesspolicy.xml 应该存在,并且应该启用跨域访问。
参考
历史
- 2011 年 10 月 2 日:初始版本