您的位置:首页 > 业界新闻

如何访问一个互联网上的xap文件

2012-09-24 21:42 483 查看
概述
众所周知,在Silverlight 2开始每个项目编译后都会打包成为一个xap文件,如果我们要访问当前xap文件中的UserControl比较容易,那我们如何访问一个外部xap文件中的内容呢?甚至于如何访问一个互联网上的xap文件呢?
本文将简单介绍一下在Silverlight中如何访问外部xap文件。
需求
现在我们先来看一下需求,大致是这样子的,在服务端我们有两个xap文件,其中MainProject.xap文件将会在MainProjectTestPage.aspx中引用,而ExternalProject.xap文件中的UserControl将会在MainProject.xap文件中访问,并进行显示,如下图所示:
现在我们来建立相关的项目,最终完成的项目结构如下图所示:

这样在编译后,将会在ClientBin文件夹下产生两个.xap文件,现在我们将在MainProject.xap文件中访问ExternalProject.xap中的UserControl。
分析
在实现这个过程中,我们将会遇到两个问题:
1.因为没有任何页面引用ExternalProject.xap文件,所以它不会下载到客户端,这一点我们可以通过编码的方式来下载它。
2.访问ExternalProject.xap中的UserControl,我们需要找到对应的程序集,以便使用反射,我们知道在xap文件是一个标准的zip文件,它会包含相关的程序集(接下来我会写一篇文章专门解释xap文件),如下图所示:
现在解决了xap文件的下载已经程序集的访问问题,我们可以着手来实现了。
实现
实现的过程也是相当简单,首先我们使用WebClient去下载xap文件,相信大家都知道该怎么做了,如下代码所示

void myButton_Click(object
sender, RoutedEventArgs
e)
{
Uri
address = new
Uri("http://localhost:4161/ClientBin/ExternalProject.xap");
WebClient
webClient = new
WebClient();
webClient.OpenReadCompleted +=
new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(address);
}
void webClient_OpenReadCompleted(object
sender, OpenReadCompletedEventArgs
e)
{
//
得到下载结果
}

这一步比较简单,接下来我们将根据下载的结果,得到相应的程序集。我们知道在xap文件中的AppManifest.xaml文件相当于一个清单,列出了当前xap文件用到的程序集(下篇文章将会介绍),它的内容如下所示:

<Deployment
xmlns="http://schemas.microsoft.com/client/2007/deployment"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

EntryPointAssembly="ExternalProject"

EntryPointType="ExternalProject.App"

RuntimeVersion="2.0.30523.6">
<Deployment.Parts>
<AssemblyPart
x:Name="ExternalProject"
Source="ExternalProject.dll"
/>
</Deployment.Parts>
</Deployment>

注意,在Deployment.Parts节点下包含了当前应用程序中所有的程序集。首先要根据下载的结果获取AppManifest.xaml文件中的内容,如下代码所示:

Stream
stream = Application.GetResourceStream(

new StreamResourceInfo(packageStream,
null),

new Uri("AppManifest.xaml",
UriKind.Relative)).Stream;
String
appManifestString = new
StreamReader(stream).ReadToEnd();


有了AppManifest.xaml中内容,就可以根据它来构造一个Deployment对象,Deployment对象提供了当前应用程序的Part和本地化信息清单,它的定义如下所示:
注意它定义了一个很重要的属性Parts,通过该属性我们就可以访问所有Deployment中的程序集。好了,现在我们看如何通过AppManifest.xaml中的内容构造Deployment对象,以及遍历其中的程序集,如下代码所示:

Deployment
deployment = (Deployment)XamlReader.Load(appManifestString);
Assembly
assembly = null;
foreach
(AssemblyPart
assemblyPart in
deployment.Parts)
{
if
(assemblyPart.Source == assemblyName)
{

String source = assemblyPart.Source;

StreamResourceInfo streamInfo =
Application.GetResourceStream(

new StreamResourceInfo(packageStream,

"application/binary"),

new Uri(source,UriKind.Relative));

assembly = assemblyPart.Load(streamInfo.Stream);

break;
}
}
return assembly;

注意,在遍历时如果我们找到程序集名等于我们想要访问的程序集,则直接返回该程序集。最终完整的LoadAssemblyFromXap方法代码如下:

Assembly
LoadAssemblyFromXap(Stream
packageStream,String
assemblyName)
{
Stream
stream = Application.GetResourceStream(

new StreamResourceInfo(packageStream,
null),

new Uri("AppManifest.xaml",
UriKind.Relative)).Stream;
String
appManifestString = new
StreamReader(stream).ReadToEnd();
Deployment
deployment = (Deployment)XamlReader.Load(appManifestString);
Assembly
assembly = null;
foreach
(AssemblyPart
assemblyPart in
deployment.Parts)
{

if (assemblyPart.Source == assemblyName)

{

String source = assemblyPart.Source;

StreamResourceInfo streamInfo =
Application.GetResourceStream(

new StreamResourceInfo(packageStream,

"application/binary"),

new Uri(source,UriKind.Relative));

assembly = assemblyPart.Load(streamInfo.Stream);

break;

}
}
return
assembly;
}


得到程序集后,再使用反射创建相关的实例,并在页面上加载,如下代码所示:

Assembly
assembly = LoadAssemblyFromXap(e.Result, "ExternalProject.dll");
UIElement
element = assembly.CreateInstance("ExternalProject.SubPage")
as UIElement;
this.holder.Children.Add(element);


运行后效果如下图所示:

跨域访问
在上面的示例中,不涉及到跨域(我会专门写一篇文章介绍)调用的问题,如果大家想访问的xap文件与当前xap文件不在同一站点中,需要添加跨域访问文件,如下代码所示:
clientaccesspolicy.xml:

<?xml
version="1.0"
encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from
http-request-headers="*"
/>
<domain
uri="*"/>
</allow-from>
<grant-to>

<resource path="/"
include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>

解决 Silverlight 调用 WCF 服务 跨域访问 和 Silverlight 引用服务后配置文件不加载的问题
2009-12-27 11:51 by Yan YAN(闫妍), 783
阅读, 1
评论,
收藏,
编辑
跨域访问,估计是Silverlight
调用WCF,都会碰到的问题,我也一样
重点,跨域文件一定要放对地方,位置一定是http://域名/clientaccesspolicy.xml
这样可以访问到才行

这个域名的根目录的实际访问目录下

我们需要把clientaccesspolicy.xml文件,放到发布WCF服务的根目录中(问题是,如果发布的载体不是IIS呢,是WPF,像上一个程序那样,这个问题先放下,今后我会研究它,给出答案)
如上面提出的问题,如果你使用了Silverlight
而你的客户端是部署在特定的服务端口上WPF,控制台等,那么这个端口,只能限制使用4502~4534之间的端口号码,然后在943端口上开启一个服务,里为Silverlight客户端提供策略文件的配置信息

clientaccesspolicy.xml
内容

<?xml version="1.0" encoding="utf-8"?>

<access-policy>

<cross-domain-access>

<policy>

<allow-from http-request-headers="*">

<domain uri="*"/>

</allow-from>

<grant-to>

<resource path="/" include-subpaths="true"/>

</grant-to>

</policy>

</cross-domain-access>

</access-policy>

Silverlight
引用服务后配置文件不加载的问题

这是由于创建的WCF
服务不是支持 Silverlight
的缘故,我有一个办法解决了,但可能不是很好,就是,创建一个如下面所示的WCF,也就是启用Silverlight功能的WCF服务。

这样,我们再引用就能看到配置信息,否则只能看到一个<configuration />
标签

下面的这个程序就是配置并调用成功的源代码,如果部署到另一台PC上,可能存在的跨域的问题,可以参考上面。

2009-06-05 13:34

Silverlight访问webService跨域问题的解决之一

调试清单

检查服务是否正在运行

检查配置

检查跨域问题

检查是否已启用异常

检查网络上的内容

检查服务是否正在运行

在 Silverlight 客户端上查找问题之前,请确认正在访问的服务正常运行。对此进行检查的一种方法是将服务地址键入 Web 浏览器。此处所需的服务地址是 ServiceReferences.ClientConfig 文件的 <endpoint> 元素中的 address 属性的值。请注意,这不是键入到“添加服务引用”对话框中的地址。“服务帮助页”功能经常可用,输入地址后将显示一个页面,指示服务是否正常运行。如果“服务帮助页”无法显示,则错误页将指示服务是否正常运行,并且会提供一个可用作调试起点的消息。

通常,测试服务是否运行的更可靠的一种方法是使用测试工具尝试与服务进行对话(如 WCF 测试客户端)。

查明是否是服务代码而不是 Silverlight 客户端代码出现问题的另一种非常可靠但有时开销较大的方法是,尝试从非 Silverlight 客户端使用服务。例如,创建新的控制台应用程序类型项目,像在 Silverlight 项目中一样对该项目执行“添加服务引用”,然后再次将服务使用代码添加到

Main()

内,就像在 Silverlight 应用程序中一样。使用

Console.WriteLine

显示结果。

检查配置

第一步是检查 Silverlight 客户端是否配置正确。您应该有一个名为 ServiceReferences.ClientConfig 的文件,该文件由“添加服务引用”工具生成。检查正在使用 IService 协定访问相关服务的 CustomerService 客户端的文件。生成的配置文件应如以下内容所示。

复制代码

<configuration>

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding

name="BasicHttpBinding_IService"

maxBufferSize="65536"

maxReceivedMessageSize="65536">

<security mode="None" />

</binding>

</basicHttpBinding>

</bindings>

<client>

<endpoint

address="http://localhost:61424/WebSite5/Service.svc"

binding="basicHttpBinding"

bindingConfiguration="BasicHttpBinding_IService"

contract="CustomerClient.CustomerService.IService"

name="BasicHttpBinding_Service" />

</client>

</system.serviceModel>

</configuration>

请注意,您添加对其引用的服务只有一个 <endpoint> 元素,并且在 Silverlight 应用程序正确配置的情况下绑定为 basicHttpBinding 绑定。

如果服务中没有 <endpoint> 元素,则您的服务可能实际上配置不正确,无法被 Silverlight 2.0 应用程序访问。Silverlight 2.0 应用程序只能与使用 SOAP 1.1 的简单 SOAP 服务对话,无法处理任何高级的 WS-* 协议,如 WS-Addressing 或 WS-Security。如果使用 ASP.NET Web 服务,则客户端应仅默认使用此简单配置。有关 ServiceReferences.ClientConfig
文件中的设置,请参阅在 Silverlight 客户端中配置 Web 服务使用。

如果使用的是服务的 WCF 技术,则应该检查客户端上的配置,即使客户端 ServiceReferences.ClientConfig 看似正确。从服务中打开 Web.config 文件并查找 <system.serviceModel> 元素。

复制代码

<system.serviceModel>

...

<services>

<service name="MyProject.Service">

<endpoint

address=""

binding="basicHttpBinding"

contract="MyProject.IService" />

<endpoint

address="mex"

binding="mexHttpBinding"

contract="IMetadataExchange" />

</service>

</services>

</system.serviceModel>

查找其协定属性引用了 Silverlight 2.0 客户端正在访问的服务的 <endpoint> 元素。确保 binding 属性的值已设置为“basicHttpBinding”。其他 <endpoint> 元素可用于具有其他绑定的其他协定。例如在前面的示例中,"mex" 终结点用于为服务提供元数据。 有关 配置服务,请参阅使用配置文件配置服务。

检查跨域问题(承载服务必须和webservice在一个服务器上)

有几个与 Silverlight 应用程序相关的 URL,区分这些 URL 对于构建可能出现的跨域问题的讨论非常重要。启动应用程序时,出现在浏览器中的 URL 称为“应用程序 URL”。此 URL 通常类似如下显示:http://localhost:1111/something/MyGraphicalApp.aspx。请注意,此处真正重要的是
XAP 文件的 URL,在此例中可能显示为 http://localhost:1111/somethingelse/MyGraphicalApp.xap,但在大多数较简单的情况下,此 URL 与承载的网页将处于相同的域中,因此可以忽略此区别。然后,查看 ServiceReferences.ClientConfig 文件中的“服务 URL”:例如
http://localhost:5678/somepath/TestService.svc 和 local.live.com/SearchService/LocalSearch.asmx。

导致跨域问题的一个常见错误是从 file:// 应用程序 URL 运行 Silverlight 应用程序。在 Visual Studio 2008 中使用 F5 功能运行 Silverlight 应用程序时,也可能会遇到此问题。若要避免此问题,请右键单击项目中的 .aspx 页并选择“在浏览器中查看”。

若要了解跨域问题,请务必了解 URL 的哪个部分指定域。域基本上是介于 http:// 和 URL 中接下来出现的第一个斜杠 / 之间的部分。其中包括端口号(如果未明确指定,则假设使用 80)等。如果应用程序 URL 的域不同于服务 URL 的域,则表明为跨域情形。甚至端口号或域名的一个部分不同,都会导致此类问题的出现。例如,您的应用程序位于
http://localhost:1111/something/MyGraphicalApp.aspx,它尝试调入
http://localhost:5678/somepath/TestService.svc,则出现跨域情形,因为 localhost:1111 是与 localhost:5678 不同的域。

跨域访问服务要求服务具有跨域策略文件。有以下两种跨域策略文件:Clientaccesspolicy.xml 和 Crossdomain.xml(放在根目录)。如果希望服务跨域运行,则必须存在其中之一。有关更多信息,请参见 使服务跨域边界可用。

有一种简便的方法可检查是否已为跨域访问正确设置服务。打开浏览器并浏览至
http://service_domain/clientaccesspolicy.xml,然后浏览至
http://service_domain/crossdomain.xml。如果存在其中之一,有效且已配置为允许跨域访问,则可以跨域访问服务。

一个常见错误是将跨域策略文件放在不是域根目录的某个位置:例如将 Clientaccesspolicy.xml 文件放在
http://localhost:5678/somepath/clientaccesspolicy.xml 而不是
http://localhost:5678/clientaccesspolicy.xml。处理较旧的(比如 .NET Framework 2.0)项目时,很容易遇到这种情形。

同时,请确保检查这些文件的语法。分析其中一个文件时出现错误将视为该文件不存在。请注意,Clientaccesspolicy.xml 和 Crossdomain.xml 文件使用不同的语法。确保为选择使用的文件类型使用适当的内容。

检查是否已启用异常

通常,Silverlight 生成的异常消息中不会提供太多的信息。详细的异常信息需要大量的空间,尤其是在需要将其转换为 Silverlight 支持的所有语言时。因此,不包括详细信息是为了使 Silverlight 下载尽可能小而在设计时作出的决定。有关如何修改 Silverlight 2.0 清单文件以启用完整异常的说明,请参阅 Silverlight 2.0 发行说明。

而且,如果访问 WCF 服务,通常不会返回服务器上所引发异常的太多信息。这是一种安全措施:通常不希望将有关服务的内部信息暴露给外界(如何查看WCF异常详情查看本博客WebService异常封装http://hi.baidu.com/evaandlean/blog/item/3b913012663286d8f7039ef9.html)。

在任何情况下(通常是在 Web 服务方案中),有用的异常信息都包含于若干外部层异常包装的 innerException 中。因此在获得一个异常时,不要仅查看异常本身。还要查看嵌套的

innerException

的所有层次结构,以提取有关问题来源的尽可能多的信息。

检查网络上的内容

调试 Silverlight 服务使用问题的最根本的方法是使用“HTTP 侦察”工具,如
http://www.fiddlertool.com/fiddler/
http://projects.nikhilk.net/webdevhelper/。这些工具将显示发生的实际 HTTP 流量。在使用该工具之前,请确保先在服务器上启用异常,如上节所述。

同时启动 Silverlight 应用程序和工具,然后让应用程序调用 Web 服务。下面是您可能会看到的一些常见模式:

1. 无:您的 HTTP 侦察工具可能配置不正确。尝试运行另一个非 Silverlight 应用程序(如一般 Web 浏览器),以确保该工具运行正常。或者,您的应用程序可能已损坏。在调用服务的位置放一个断点,以确保实际调用了服务。您可能还存在配置问题,在这种情况下应参考前面的配置一节。您可能会尝试从 file:// 或 https:// URL 承载应用程序,或者尝试调用 https:// 服务。

2. 仅服务请求:如果您的网络上看到对服务的实际请求,则您已经避免了跨域情形。确定该地址是否为预期的地址。查看网络上返回的内容。内容是否已超时,或者遇到 404 错误?您的服务或甚至 WCF 本身可能设置不正确。是否返回了 SOAP 错误?如果是,请仔细阅读错误中的内容,通常其中包含了用于调试该问题的足够信息。一般情况下,请仔细查看请求和回复,包括正文和 HTTP 标头。是否已删除任何内容以便让代理通过编译?服务实际上可能要求使用删除的某些项。例如,它可能要求使用某些
SOAP 标头。

3. 先请求 Clientaccesspolicy.xml(之后可能是 Crossdomain.xml),然后请求服务:您存在跨域情形,但是已成功设置跨域策略文件。现在,这种情形和模式 2 基本相同。

4. 仅请求 Clientaccesspolicy.xml,无其他:很大程度上这是因为 Clientaccesspolicy.xml 格式不正确,或者它包含禁止跨域访问的策略。

5. 请求 Clientaccesspolicy.xml,然后请求 Crossdomain.xml,无其他:基本上,很可能是跨域策略文件出现问题。是否收到 404 错误?请检查是否以正确的方式承载文件以及是否在正确的位置。是否实际收到了文件?请检查是其格式不正确,还是禁止了跨域访问

分析Silverlight跨域调用

在silverlight开发的过程中不免要遇到跨域的问题,在这里以跨域调用Webservice为例子来分析一下跨域的问题。

先介绍一下我的测试项目,我用flash和silverlight一同来调用一个webservice,一个flash客户端,一个silverlight客户端,一个web项目来host
flash和silverlight,再加上一个webservice端。
flash发布到web项目的swf文件夹下。
web项目中的clienttestpage.html中的sl和flash来调用webservice。

具体如何调用webservice我这里就略去了。
我的webservice里有一个方法
[WebMethod]

publicstring SayHello(string name) {

return"Hello " + name;

}

webservice

Html Host页面

这里先用silverlight来调用,在输入用户名都点击invoke按钮看看发声了什么。
在firefox中打开firebug的网络监视器

这里发现他先去webservice所在的域的根目录下请求一个 clientaccesspolicy.xml
的文件,在没有到后又去请求一个crossdomain.xml的文件,同样也是没有找到,返回404。

好,这里我在webservice域根下放入一个clientaccesspolicy.xml
clientaccesspolicy.xml

代码
<?xml version="1.0" encoding="utf-8"
?>

<access-policy>

<cross-domain-access>

<policy>

<allow-from
http-request-headers="*">

<domain
uri="*"/>

</allow-from>

<grant-to>

<resource
include-subpaths="true" path="/"/>

</grant-to>

</policy>

</cross-domain-access>

</access-policy>

因为webservice有requestheaders的请求,所以要加上红色部分。

再次调用看看是什么情况
请求到了clientaccesspolicy.xml
后就去真正请求webservice文件了。
并且得到了返回值。

接下来,去掉clientaccesspolicy.xml,加入crossdomain.xml
crossdomain.xml
<?xml version="1.0"?>

<cross-domain-policy>

<allow-access-from domain="*"/>

<allow-http-request-headers-from domain="*" headers="*"/>

</cross-domain-policy>

再次调用
在没有找到clientaccesspolicy.xml的情况下,去请求crossdomain.xml文件,得到响应后就正式请求webservice文件,并且也得到了返回值。

接下来看flash
这里用as2.0做的。

他一开始直接就请求了crossdomain.xml,并没有去请求clientaccesspolicy.xml。
再输入用户名后,直接向webservice post数据,得到返回值。

好接下来看看as3的flash又会如何。

机制有些改变,一开始没去请求xml。

输入用户名,调用

再看看没有找到xml的情况

好了在看看网上我搜索到的一些说法。

“出于安全考虑,FlashPlayer默认的安全设置是不允许进行跨域操作的。即便是同一个网站,如果用不同的方式访问,也会被FlashPlayer认为是跨域操作。
为解决Flash/Flex系统中的跨域问题,提出了crossdomain.xml跨域策略文件。有了它,就可以解决跨域问题。”

“SilverLight要实现跨域访问,必须在服务端被访问域的直接域名下,配置clientaccesspolicy.xml(或
crossdomain.xml)文件,即可以访问 http://{domainName}/clientaccesspolicy.xml。

提出问题
关于crossdomain.xml
和 clientaccesspolicy.xml
的区别。
1、这两个文件真的是可以任选其一吗?
2、这两个文件分别需要被放在服务端还是客户端?
3、不管后台服务部署在IIS还是其它环境中,这两个文件都可以使用吗?

解答
1.silverlight在使用中可以任选其一,建议直接使用clientaccesspolicy.xml。flash只能使用crossdomain.xml。
2.都是必须在服务端被访问域的直接域名下

3.都可以使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: