大佬教程收集整理的这篇文章主要介绍了WCF服务宿主及其跨域问题,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
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 !"; } }
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用户调用服务接口:
@H_255_18@mainPage.xaml:
<Grid x:Name="LayoutRoot" BACkground="White"> <TextBlock Name="txtblkStr" HorizontalAlignment="Left" Height="25" Margin="73,63,0" textwrapping="Wrap" Text="" VerticalAlignment="Top" Width="170"/> <Button Content="点击获取" HorizontalAlignment="Left" Height="24" Margin="73,93,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
以上是大佬教程为你收集整理的WCF服务宿主及其跨域问题全部内容,希望文章能够帮你解决WCF服务宿主及其跨域问题所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。