技术标签: C# 跨域 宿主 silverLight WCF wcf silverlight
WCF服务不是一个能单独执行的程序,需要寄宿在相关的可执行程序上执行,常见的宿主方式有IIS, 控制台(Winform,wpf), Windows Service这几种方式,在使用Silverlight调用发布Wcf服务会发生跨域错误如图:
什么是跨域呢? 一句话,同一个IP,同一个网络协议,同一个端口号,三者都同时满足就是同一个域,否则就是跨域访问,需要配置相应的跨域策略才能正常访问,所以Silverlight在调用wcf服务时由于出现端口号的不同所以发生跨域访问,所以需要配置相应的跨域策略文件,即clientaccesspolicy.xml。
本文主要介绍如何使用silverlight跨域访问wcf服务,顺带介绍wcf服务宿主控制台和windows service的方式,点击这里可以下载我测试的源码,开发环境为window7 vs2012 .NETFramework,Version=v4.5
整个解决方案如图:
整个解决方案有5个项目,SLCallWcfService和SLCallWcfService.Web是Silverlight项目及其web项目用于调用wcf服务,WcfHostOnConsole是一个控制台项目,提供wcf的控制台宿主,WcfHostOnWindService是一个Windows 服务项目,提供wcf的windows服务宿主,WcfServiceDll是一个类库项目,提供对wcf服务的设计和实现。
WcfServiceDll项目总的类如图:
ITestService是一个服务接口,只提供一个方法,返回一个字符串。
namespace WcfServiceDll
{
/// <summary>
/// 服务接口
/// </summary>
[ServiceContract]
public interface ITestService
{
/// <summary>
/// 接口提供方法
/// </summary>
/// <returns></returns>
[OperationContract]
string GetTestStr();
}
}
/// <summary>
/// 服务实现
/// </summary>
public class TestService : ITestService
{
public string GetTestStr()
{
return "hello world !";
}
}
IDomainService代码:
namespace WcfServiceDll
{
[ServiceContract]
public interface IDomainService
{
[OperationContract]
[WebGet(UriTemplate = "ClientAccessPolicy.xml")]
Message ProvidePolicyFile();
}
}
public class DomainService : IDomainService
{
static string fileContent = string.Empty;
public System.ServiceModel.Channels.Message ProvidePolicyFile()
{
if (fileContent.Length == 0)
{
StreamReader fileStream = new StreamReader("ClientAccessPolicy.xml");
fileContent = fileStream.ReadToEnd();
fileStream.Close();
}
StringReader sr = new StringReader(fileContent);
XmlReader reader = XmlReader.Create(sr);
System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
return result;
}
}
<?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>
注意要添加ystem.ServiceModel.dll, System.ServiceModel.Web.dll, System.Runtime.Serialization.dll的引用
wcf服务的宿主其实很简单,在我们的服务写好了之后无非就是创建服务,开启服务,然后在结束时关闭服务,那么我们的宿主程序中其实就是为wcf服务提供这样的一个执行环境吧(个人愚见),所以这里我们的WcfServiceDll中的服务要宿主在WcfHostOnConsole控制台中,则在控制台中开启我们的服务(注意有两个服务哦),然后配置好我们的App.config文件即可。
WcfHostOnConsole中的App.config文件配置:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="WCFCrossDomainService">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DomainServiceBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WCFCrossDomainService" name="WcfServiceDll.TestService">
<endpoint address="" binding="basicHttpBinding" contract="WcfServiceDll.ITestService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9898/TestService/" />
</baseAddresses>
</host>
</service>
<service name="WcfServiceDll.DomainService">
<endpoint address="" behaviorConfiguration="DomainServiceBehavior"
binding="webHttpBinding" contract="WcfServiceDll.IDomainService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9898/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WcfServiceDll.TestService));
host.Open();
Console.WriteLine("数据服务开启");
ServiceHost crossDomainserviceHost = new ServiceHost(typeof(WcfServiceDll.DomainService));
crossDomainserviceHost.Open();
Console.WriteLine("跨域服务开启");
Console.ReadLine();
host.Close();
}
}
现在我们想想我们的跨域策略配置文件clientaccesspolicy.xml应该放在哪?因为我们的服务WcfServiceDll中的程序是被我们的控制台程序调用的,则起运行在我们控制台程序下,那么想要的读取配置策略文件clientaccesspolicy.xml也就应该放在控制台的跟目录中了,即bin/Debug中和WcfHostOnConsole.exe一个目录中。
这样我们生成我们的控制台程序,然后到项目bin/Debug中去找到控制台程序WcfHostOnConsole.exe即可运行,也可以设置WcfHostOnConsole为启动项运行,当然这样不方面后面的测试;
这样我们的数据服务和跨域服务都启动了,接下来在我们的silverlight项目SLCallWcfService中添加服务引用http://localhost:9898/TestService/如图:
然后我们的主界面MainPage.xaml中添加一个textBlock用于显示调用结果,一个Button用户调用服务接口:
MainPage.xaml:
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Name="txtblkStr" HorizontalAlignment="Left" Height="25" Margin="73,63,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="170"/>
<Button Content="点击获取" HorizontalAlignment="Left" Height="24" Margin="73,93,0,0" VerticalAlignment="Top" Width="72" Click="Button_Click_1"/>
</Grid>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
TestServiceClient client = new TestServiceClient();
client.GetTestStrCompleted += new EventHandler<GetTestStrCompletedEventArgs>(GetTestStrCompleted);
client.GetTestStrAsync();
}
private void GetTestStrCompleted(object sender, GetTestStrCompletedEventArgs e)
{
this.txtblkStr.Text = e.Result.ToString();
}
}
好了,这样我们的在我们服务开始后就可以运行我们的silverlight项目然后调用测试
运行成功结果:
好了,这样我们的wcf宿主在控制台程序中的跨域问题就解决了,同样我们宿主在Winform和wpf程序中的解决方案也是一样的。下面我们用同样的方法来测试宿主在windows 服务中。
什么是windows服务呢,简单的将就是长时间运行在你电脑上的程序,它可以在开始时自动运行,延迟运行,也可以被禁止运行,这样就可以为电脑上的其他运行程序长时间的提供数据提供服务。将我们的wcf服务宿主在windows服务上,这样我们的wcf在开机是变可以方便的启动,并且长时间运行在计算机上,是一种不错的宿主方式。
在我们的项目中WcfHostOnWindService即是一个windows服务项目,提供给wcf宿主的,那么怎么样将wcf服务宿主在windows服务上?怎么样注册我们的服务呢?下面则是具体的做法:
如图是WcfHostOnWindService项目的结构:
既然它为wcf提供宿主,则也需要配置我们的wcf服务端App.config这个配置和上面的控制台宿主配置一样,TestService是新建每个windows服务自带的一个类,我们查看代码发现提供的了OnStart和OnStop两个函数,自然明白了就是服务启动和关闭时执行的函数,这样我们很容易就想到了,我们要在windows服务启动时启动我们的wcf服务,关闭时关闭我们的wcf服务,代码:
public partial class TestService : ServiceBase
{
public TestService()
{
InitializeComponent();
}
private ServiceHost host = null;
private ServiceHost crossDomainserviceHost = null;
protected override void OnStart(string[] args)
{
host = new ServiceHost(typeof(WcfServiceDll.TestService));
host.Open();
crossDomainserviceHost = new ServiceHost(typeof(WcfServiceDll.DomainService));
crossDomainserviceHost.Open();
}
protected override void OnStop()
{
host.Close();
crossDomainserviceHost.Close();
host = null;
crossDomainserviceHost = null;
}
}
一. 我们在TestService的设计界面右键选择“添加安装程序”如图:
来到我们的ProjectInstaller设计界面,设置serviceProcessInstaller1的Account属性为LocalSystem:
然后设置serviceInstaller1即我们的服务的一些属性,这里我们设置了服务的名称为TestService, 描述为:测试wcf跨域
好了,到这步我们就可以安装注册我们的服务了,我们先生成这个windows服务项目WcfHostOnWindService,发现再bin/Debug中有了WcfHostOnWindService.exe,接下来就要用它来安装和注册服务,另外还需要一个需要用工具一起在dos中执行安装和卸载:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
安装命令:
1. 打开cmd窗口
2. 键入C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe和服务路径(中间空格分隔)
则已我项目的命令为:C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe E:\MyWorkSpace\WCFCrossDomain\WcfHostOnWindService\bin\Debug\WcfHostOnWindService.exe
运行结果:
查看服务安装成功:
卸载需要加上/u命令:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u E:\MyWorkSpace\WCFCrossDomain\WcfHostOnWindService\bin\Debug\WcfHostOnWindService.exe
每次这样写命令很麻烦,则可以将这个两个命令写在批处理文件.bat文件:
安装并开启:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe %cd%\WcfHostOnWindService.exe
@net start TestService
@echo ****************************************************************************
@echo 注册成功
@echo ****************************************************************************
@pause
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u %cd%\WcfHostOnWindService.exe
@echo ****************************************************************************
@echo 卸载成功
@echo ****************************************************************************
@pause
好了这个我们的windows服务就完成了,下面我们同样将我们的策略配置文件放到与WcfHostOnWindService.exe一个目录中,因为我的服务名称和服务地址都是一样的,不需要从新添加服务引用直接启动silverlight项目测试:
没有成功!!!!!!!!!!!!!至少我试了很多次都没有成功,这也是我记录的原因了,为什么没有成功呢,一样的方法在控制台成功在windows服务则失败了,唯一的可能就是windows服务程序找不到跨域策略配置文件clientaccesspolicy.xml,怎么办呢?
既然他自己找不到,那么我们就主动为它指定目录,修改我们的DomainService.cs,指定clientaccesspolicy.xml的路径:
public System.ServiceModel.Channels.Message ProvidePolicyFile()
{
string location = System.Reflection.Assembly.GetExecutingAssembly().Location;
location = location.Substring(0, location.LastIndexOf('\\')) + "\\ClientAccessPolicy.xml";
if (fileContent.Length == 0)
{
StreamReader fileStream = new StreamReader(location);
fileContent = fileStream.ReadToEnd();
fileStream.Close();
}
StringReader sr = new StringReader(fileContent);
XmlReader reader = XmlReader.Create(sr);
System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
return result;
}
经过以上测试windows 服务为宿主的wcf确实存在以上路径问题,至少我是遇到了,然后这样修改后成功了,如果有朋友有更好的解决方法欢迎指正!
源码下载:http://download.csdn.net/detail/dangercheng/6730461
文章浏览阅读788次,点赞14次,收藏19次。这个puzzle 的爽文至此结束了!再次感谢一下CSDN和CSDN平台上勤奋的IT小猴子们~希望和大家一起思考,多多讨论。
文章浏览阅读546次。JS的俩种引入方式:1.<!--js的引入方式1--> <script> /*网页中的弹框*/ alert("js的学习!!") </script>2.<!-- js的引入方式2 src=引入文件的路径 charset=指定引入的编码 注意:引入js的时候千万不要二合一 ..._publish.js 里的变量怎么引入
文章浏览阅读829次,点赞2次,收藏9次。本文介绍C语言预处理指令 #pragma,介绍预处理的#运算符、##运算符_#pragma
文章浏览阅读2.1w次,点赞11次,收藏35次。用法finfo函数是根据括号中的类型来获得信息,获得符合这个类型的数型例1:import numpy as npa=np.array([[1],[2],[-1],[0]])b=np.maximum(a,np.finfo(np.float32).eps)print(b) 结果:[[1.0000000e+00] [2.0000000e+00] [1.1920929e-07] [..._np.finfo(float).eps
文章浏览阅读5.5k次。Keras学习笔记---保存model文件和载入model文件保存keras的model文件和载入keras文件的方法有很多。现在分别列出,以便后面查询。keras中的模型主要包括model和weight两个部分。保存model部分的主要方法:一是通过json文件Json文件[python] view plain co_model文件如何保存的
文章浏览阅读175次。软件文档的编写是在计算机软件的生存期中一直都存在的吗?如果没有这个软件文档,编写好的软件可以正常运行吗?1、书中写道,计算机软件的生存期包括6个步骤:计划、需求分析、设计、程序编写、测试和运行维护。,也就是重中之重的步骤是哪一个?个人感觉一定是前3个中的一个,但是计划、需求分析、软件设计哪个更重要就不是很清楚了。2、书中第二章介绍了统一建模语言UML及建模工具,还有许多基于UML语言描述的关系图。3、现在的软件开发主流是面向对象开发,为何书中还要单独拿出一章节讲述。UML图的设计是在计算机软件生存期中的。
文章浏览阅读1.3w次,点赞6次,收藏17次。##本例子使用的是R自带的数据集irisirisData=iris ##重命名列names(irisData)=c("萼长","萼宽","瓣长","瓣宽","种类") ##处理后的数据格式如下所示: >head(irisData, 3) 萼长 萼宽 瓣长 瓣宽 种类 1 5.1 3.5 1.4 0.2 _r比例分层抽样strata
文章浏览阅读2.5k次,点赞3次,收藏18次。【代码】mysq连接详解(内外连接,左右连接)_jasync-mysql-2.1.7 mysq连接
文章浏览阅读3.8w次,点赞27次,收藏124次。Android Studio 除了支持虚拟机调试之外还支持真机调试,本人使用的是小米6x作为测试机子。**一、Usb驱动准备**1.打开AS的SDK Manager,在SDK Tools下勾选Google Usb Driver,点击Ok。AS会自动下载Usb驱动,速度挺快。一定要记住下载驱动保存的位置,我的路径是R:\Coding\Android SDK2.下载和真机一样版本的SDK ..._as怎么真机调试
文章浏览阅读1.1k次。第一部分 nestjs + fastify + typeorm项目初始体验一、概述利用nestjs框架搭建服务端技术架构,目前使用的包如下:fastifymysqltypeorm二、工程初始化$ npm i -g @nestjs/cli$ nest new project-name三、配置Fastify核心包1、在工程根目录下执行如下命令:$ npm i --save @nestjs/platform-fastify2、在src目录中编辑main.ts文件,具体内容如下:im_nestjs fastify
文章浏览阅读60次。无线网实验配置动态负载均衡,倒霉催的AP上线不了,看个视频学一下。
文章浏览阅读442次,点赞9次,收藏6次。闭包可以捕获并保持外部函数的状态,使得函数具有记忆功能。第 15题考察了多线程和多进程的区别及其优缺点,要求面试者对 Python 中常见的并发编程模型有一定的理解和评估能力。第 14题考察了上下文管理器的概念和使用,要求面试者对 Python 中的资源管理和代码可读性有一定的掌握能力。第 13 题考察了异常处理机制的概念和使用,要求面试者对 Python 中的错误处理和调试有一定的熟悉程度。第 12 题考察了装饰器的概念和使用,要求面试者对 Python 中的高级特性有一定的理解和应用能力。