Silverlight+WCF+ArcGIS程序开发以及部署过程中的问题总结

  开卷有益。

  最近的这个项目搞的我苦笑不得,一个拉了3-4年的业务系统(哎,悲催的项目啊),其中用到了WCF服务,此服务是IIS宿主服务,主要为后续的Silverlight程序提供相应的业务服务。在Silverlight程序中用到了ArcGIS,用来加载地图。Silverlight程序通过引用本地的WCF服务获取到了相应的代理。在我的Silverlight程序中,为了后续的地图服务地址的灵活配置将地图服务的地址放到了承载Silverlight网站的Web.Config文件配置节中。基本情况就是这样,结果发布系统后部署到服务器上之后,产生的问题真是千奇百怪!

问题1:Silverlight程序无法加载。

这个问题最常见,部署的问题。我们部署的Web服务器是WIN2003系统,在IIS6下需要给Silverlight承载网站添加MIME类型以处理xap和xaml。需要添加的两个MIME类型为:

[.xaml application/xaml+xml]

[.xap application/x-Silverlight-app]

Silverlight程序中动态读取承载网站上的SVC服务文件。

在我们开发的项目中,Silverlight程序的承载网站和WCF服务的宿主相同,这样我们的SVC地址可以可以通过下述代码获取。

new Uri(Application.Current.Host.Source, "../GIMHostService.svc")

  另外,在项目初期的时候,为了防止最终程序部署时WCF服务与业务系统的分离,实现了Silverlight动态加载WCF服务,此方法也是基于网上的一些资料整理完成:

  Silverlight程序中WCF服务动态加载的单例实现:

Silverlight程序中WCF服务动态加载的单例实现 
 1      /// <summary>
2 /// 多线程单例模式
3 /// </summary>
4 public class SingletonClient
5 {
6 private static volatile GIMHostServiceClient instance = null;
7 private static object lockHelper = new object();
8 private SingletonClient() { }
9 public static GIMHostServiceClient Instance
10 {
11 get
12 {
13 if (instance == null)
14 {
15 lock (lockHelper)
16 {
17 if (instance == null)
18 {
19
20 string serviceUri = new Uri(Application.Current.Host.Source, "../GIMHostService.svc").ToString();
21 if (string.IsNullOrEmpty(serviceUri)) return null;
22
23 object[] paras = new object[2];
24 //此处的Binding格式必须和WCF服务的HOST主机上的配置一致,否则会返回404No Found错误。
25 BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
26 binding.MaxBufferSize = int.MaxValue;
27 binding.MaxReceivedMessageSize = int.MaxValue;
28 EndpointAddress address = new EndpointAddress(new Uri(serviceUri, UriKind.Absolute));
29
30 paras[0] = binding;
31 paras[1] = address;
32
33 ConstructorInfo constructor = null;
34
35 try
36 {
37 Type[] types = new Type[2];
38 types[0] = typeof(System.ServiceModel.Channels.Binding);
39 types[1] = typeof(System.ServiceModel.EndpointAddress);
40
41 constructor = typeof(GIMHostServiceClient).GetConstructor(types);
42 }
43 catch (Exception)
44 {
45 return null;
46 }
47
48 if (constructor != null)
49 instance = (GIMHostServiceClient)constructor.Invoke(paras);
50 }
51 }
52 }
53 return instance;
54 }
55 }
56 }

  WCF服务SVC文件配置:

<%@ ServiceHost Language="C#" Debug="true" Service="HN.GIM.WCFService.GIMService" %>

  WCF服务承载网站的服务配置:

 <system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="HN.GIM.WCFService.GIMServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<!--此处的behaviorConfiguration应该和name名称保持一致,否则可能会出错(没有经过验证)。此处的名称必须和SVC文件中的Service名称一致s-->
<service behaviorConfiguration="HN.GIM.WCFService.GIMServiceBehavior" name="HN.GIM.WCFService.GIMService">
<endpoint address="" binding="basicHttpBinding" contract="HN.GIM.WCFService.Contract">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>

  上述的各项设置基本就完成了我们的WCF服务的开发以及Silverlight的引用。

Silverlight程序访问ArcGIS地图服务地址产生跨域问题。

  在这个项目开发部署的过程中,这个跨域问题最头疼,但最终还是解决掉了。过程中,被逼无奈都看英文博客了(以前从来没看过,一直惧怕英文,没想到咱还能看懂...
好神奇!),而最终解决的方法更是让我惊呼不已,不怪天,不怪地,只怪自己手贱!害人害己啊...且听我慢慢道来:

  我们的服务器部署在局域网内的某台机器上,IP为192.168.2.101,ArcGIS Server也安装在这台机器上,那么ArcGIS默认的端口为80端口,如果想要在外网中访问相应的ArcGIS服务,就得需要路由器上的端口映射。另外,我们的业务系统部署在了IIS上通过8003端口进行访问,那么我们在客户端通过8003端口可以访问业务系统,之后可通过业务系统查看相应的Silverlight程序,在查看Silverlight程序的过程中,会通过80端口去请求GIS服务数据,在这个过程中就产生了跨域操作。

  我们的跨域问题是从ArcGIS服务地址产生的,错误描述为:

Unhandled Error in Silverlight Application A security exception occured while trying to connect to the REST endpoint. Make sure you have a cross domain policy file available at the root for your server that allows for requests from this application.

  OK,根据这个提示错误消息,在网上找了一系列的资料,通过配置两个跨域策略文件到wwwroot目录下即可解决(网上是这么说的,我也就这么做了)。可是,问题依旧,莫非是ArcGIS地图服务发布的有问题?可惜我对ArcGIS地图服务的熟悉程度仅仅限于应用的层次,原理、底层什么乱七八糟的根本一窍不通。研究了一天的ArcGIS服务的相关东西,企图从ArcGIS服务上去找到解决方案的思路我认为是行不通了。

  之后,我想到既然ArcGIS的访问会产生跨域问题,Silverlight程序如果访问不同端口下的WCF服务应该也会产生跨域的操作,会不会引发同样的问题呢?如果照样引发跨域问题,那么只能说明跨域策略文件没有按照正确的跨域策略执行!果然,我将服务器上的WCF服务配置到另外一个端口下,用原来的业务系统去访问另外一个端口下的WCF服务,结果报告了错误:

尝试向 URI“http://localhost:8001/AccountService.svc”发出请求时出错。这可能是由于试图以跨域方式访问服务而又没有正确的跨域策略,或策略不适用于 SOAP 服务。您可能需要与该服务的所有者联系,以发布跨域策略文件并确保该文件允许发送 SOAP 相关的 HTTP 标头。出现此错误也可能是由于使用的是 Web 服务代理中的内部类型而没有使用 InternalsVisibleToAttribute 属性。有关详细信息,请参阅内部异常。

  OK,毫无疑问,只能说明服务器端的跨域文件没有按照正确的跨域策略执行。之后利用Fiddler监听了ArcGIS官网提供的地图服务和服务器上的ArcGIS服务,通过HTTP请求的比对发现:他们两个都能够读取到跨域文件clientaccesspolicy.xml,但他们的content-type却不一样,官网上的为text/xml,而服务器上的为application/xaml+xmlt,震惊了!怎么可能?为什么???莫非......MIME文件添加错了?赶紧去服务器上去看,原来当初部署系统(不是我部署的~~)的时候添加.xaml的MIME类型时,给添加错了,写成了.xml...,最要命的是,这个类型加载了默认网站上,而没有添加到业务系统的虚拟目录上!结果导致了跨域策略始终无法正确解析。修改过来之后,OK了!

  终于告一段落了,还不错,在解决问题的过程中了解了其他方面的一些知识点。也算是对自己的一个安慰吧!

转载于:https://www.cnblogs.com/joinfunny/archive/2012/02/08/2341593.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值