我们往往需要调用已建好的WCF,Web Service,Wcf Ria Service,这些调用的程序项目往往是另开一个的一个解决方案,这往往导致调用服务者和发布服务者不是同一个服务器上,即使在同一服务器上,因程序的端口好不同,而会产生跨域的问题。
(一)原因分析:
Silverlight 在默认情况下只允许源站点通信。例如,在 http://contoso.com/mycontrol.aspx 上承载的 Silverlight 控件默认只能访问同一域中的服务(例如 http://contoso.com/service.svc),而不能访问位于 http://fabrikam.com/service.svc 的服务。这可以避免在 http://contoso.com 域上承载的恶意 Silverlight 控件对 http://fabrikam.com 域上承载的服务调用未授权操作。
(二)跨域粉墨登场
就是因为这些原因,而跨域能解解决不同站点调用非本地站点服务,所以跨域就水到渠成的登场了
(三)如何跨域
只需要在你的*.Web服务端的根目录下放上两个文件clientaccesspolicy.xml 和crossdomain.xml
(1)clientaccesspolicy.xml 以配置服务允许跨域访问
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<!--只允许从其他域中的一个访问,如http://contoso.com
<allow-from http-request-headers="*">
<domain uri="http://contoso.com"/>
</allow-from>
-->
<!--允许访问 HTTPS 服务
<allow-from http-request-headers="*">
<domain uri=”http://*”/>
</allow-from>
-->
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
(2) crossdomain.xml 该文件必须将整个域标记为 public
<?xml version="1.0" ?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
(四)实战训练
(1)新建项目SilverlightWCF,并在*.Web端添加一个WCF服务,记得一定是选择“启动了Silverlight的WCF服务”,如下图
代码如下
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace SilverlightWCF.Web
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CustomerService
{
[OperationContract]
public int CountUsers()
{
return 2;
}
[OperationContract]
public User GetUser(int id)
{
if (id == 1)
{
return new User() { IsMember = true, Name = "Paul", Age = 24 };
}
else
{
return new User() { IsMember = false, Name = "John", Age = 64 };
}
}
// 在此处添加更多操作并使用 [OperationContract] 标记它们
}
//需要注意点
//(1)默认情况下,DataContractSerializer 序列化所有公开可见的类型,包括这些类型的所有公共的读/写属性和字段
// 不需要应用 DataContractAttribute 和 DataMemberAttribute 以选择使用序列化过程
//(2)如果不使用“启用 Silverlight 的 WCF 服务”模板创建 WCF 服务,则必须确保使用 BasicHttpBinding 配置 WCF 服务,以便支持该服务。
//(3)使用“启用 Silverlight 的 WCF 服务”模板时,Web.config 文件会自动改为启用 ASP.NET 兼容模式,以便于将您的支持服务的 Silverlight 应用程序与 ASP.NET 安全模型相集成
// 这样您就可以完成很多工作,例如,可以限制仅通过身份验证的用户拥有对特定服务的访问权限,或者限制拥有特定角色的用户拥有访问权限
// 启动ASP.NET兼容模式:在web.config文件中产生AspNetCompatibilityRequirements 特性配置为允许 ASP.NET 兼容模式。
public class User
{
public bool IsMember { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
(2)新建一个项目,叫InvokeSilverlightWCF,添加服务引用。如果没有在项目SilverlightWCF.Web下添加两个跨域文件clientaccesspolicy.xml 和crossdomain.xml 就会报错,报错如下:
尝试向 URI“http://localhost:6053/CustomerService.svc”发出请求时出错。这可能是由于试图以跨域方式访问服务而又没有正确的跨域策略,或策略不适用于 SOAP 服务。您可能需要与该服务的所有者联系,以发布跨域策略文件并确保该文件允许发送 SOAP 相关的 HTTP 标头。出现此错误也可能是由于使用的是 Web 服务代理中的内部类型而没有使用 InternalsVisibleToAttribute 属性。有关详细信息,请参阅内部异常。
解决这个问题,如前面所述方法就可以解决了
(五)后续的话题
上面所说的是调用自己建的服务,如果存在跨域问题,自己想添加两个跨域文件clientaccesspolicy.xml 和crossdomain.xml 是非常容易的,就可以解决问题。但是像调用
中国气象局的天气预报服务http://www.webxml.com.cn/WebServices/WeatherWebService.asmx,你不可能叫别人为你一个人添加clientaccesspolicy.xml 和crossdomain.xml 跨域问题吧,因为WebService在其他客户的时不会存在这样的问题。
既然上面的路行不通,我的做法就是在Silverlight应用程序的服务端新建一个WCF,而这个WCF中的方法调用http://www.webxml.com.cn/WebServices/WeatherWebService.asmx的服务方法,然后Silverlight应用程序的Web端就具有这些服务方法了,在同Silverlight的Client端添加Silverlight的WCF服务,这个过程就不会发生跨域的问题了,因为他们在同一个解决方案域中。这种办法相当于把不能被Siilverlight调用服务,经过Silvelight服务端包裹后,就供Silverlight的Client调用。
关于Silvelight的跨域问题就写到这里了,凌晨1:37该睡觉了!