WCF之一
WCF(Windows Communication Foundation)的概念这里就不多说了,google一下就知道了。
必须知道的是,WCF的服务是不能孤立的存在的,需寄宿于一个运行的的进程中(我们称之为宿主),为服务指定宿主的过程成为服务寄宿。服务寄宿有两种方式:一种是自我寄宿;另一种是通过IIS将服务寄宿于IIS进程中。
接下来就先来看看第一种寄宿方式——自我寄宿。
首先,新建一个空的解决方案,添加如图所示项目
每个项目的描述及项目之间的关系如下:
- Contracts:类库项目,定义服务契约(Service Contract),引用System.ServiceModel程序集;
- Services:类库项目,提供对WCF服务的实现。定义在该项目中的所有WCF服务实现了定义在Contracts中相应的服务契约,所以Services具有对Contracts项目的引用;
- Hosting:控制台应用程序(宿主),实现对定义在Services项目中的服务的寄宿,引用Contracts、Services和System.ServiceModel程序集;
- Client:控制台应用程序(客户端),引用System.ServiceModel程序集。
Tag:有关更多System.ServiceModel,请点击http://msdn.microsoft.com/zh-cn/library/vstudio/system.servicemodel.aspx
创建服务契约:一般地,通过接口的形式定义服务契约。通过下面的代码,将一个接口ITestWcf定义成服务契约。WCF广泛采用基于自定义特性(Custom Attribtue)的声明式编程模式,我们通过在接口上应用System.ServiceModel.ServiceContractAttribute特性将一个接口定义成服务契约
using System.ServiceModel; namespace Contracts { [ServiceContract] public interface ITestWcf { [OperationContract] string HelloWord(); } }
创建服务:WCF服务TestWcfService定义在Services项目中,实现了服务契约接口ITestWcf,实现了所有的服务操作
using Contracts; namespace Services { public class TestWcfService : ITestWcf { public string HelloWord() { return "Hello Word"; } } }
自我寄宿:在实现寄宿之前,先了解些关键概念。
WCF服务需要依存一个运行着的进程(宿主),服务寄宿就是为服务指定一个宿主的过程。WCF是一个基于消息的通信框架,采用基于终结点(Endpoint)的通信手 段。终结点由地址(Address)、绑定(Binding)和契约(Contract)三要素组成。由于三要素应为首字母分别为ABC,所以就有了易于记忆的公式:Endpoint = ABC。一个终结包含了实现通信所必需的所有信息,我们可以这样认识终结点的ABC:
地址(Address):地址决定了服务的位置,解决了服务寻址的问题,意味着标识服务在哪里
绑定(Binding):绑定实现了通信的所有细节,包括网络传输、消息编码,以及其他为实现某种功能(比如安全、可靠传输、事务等)对消息进行的相应处理。WCF中具有一系列的系统定义绑定,比如BasicHttpBinding、WsHttpBinding、NetTcpBinding等,意味着信息如何传输
契约(Contract):契约是对服务操作的抽象,也是对消息交换模式以及消息结构的定义。意味着信息具体是什么
在了解了ABC后,再来看代码:
using System; using System.ServiceModel; using System.ServiceModel.Description; using Contracts; using Services; namespace Hosting { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(TestWcfService))) { host.AddServiceEndpoint(typeof(ITestWcf), new WSHttpBinding(), "http://127.0.0.1:9999/testwcfservice"); if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) { ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); ; behavior.HttpGetEnabled = true; behavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/testwcfservice/metadata"); host.Description.Behaviors.Add(behavior); } host.Opened += delegate { Console.WriteLine("TestWcfService已经启动,按任意键终止服务!"); }; host.Open(); Console.Read(); } } } }
松耦合是SOA的一个基本的特征,WCF应用中客户端和服务端的松耦合体现在客户端只须要了解WCF服务基本的描述,而无须知道具体的实现细节,就可以实现正常的服务调用。WCF服务的描述通过元数据(Metadata)的形式发布出来。WCF中元数据的发布通过一个特殊的服务行为ServiceMetadataBehavior实现。在上面提供的服务寄宿代码中,我们为创建的ServiceHost添加了ServiceMetadataBehavior,并采用了基于HTTP-GET的元数据获取方式,元数据的发布地址通过ServiceMetadataBehavior的HttpGetUrl指定。在调用ServiceHost的Open方法对服务成功寄宿后,我们可以通过该地址获取服务相关的元数据。在IE地址栏上键入http://127.0.0.1:9999/testwcfservice/metadata,你将会得到以WSDL形式体现的服务元数据,部分如图
当然,一般不会直接通过编码的方式进行终结点的添加和服务行为的定义,而是通过配置的方式进行。上面的代码可以用如下的配置代替
<?xml version='1.0' encoding='utf-8'?> <configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="metadataBehavior"> <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:9999/testwcfservice/metadata" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="Services.TestWcfService" behaviorConfiguration="metadataBehavior"> <endpoint address="http://127.0.0.1:9999/testwcfservice" binding="wsHttpBinding" contract="Contracts.ITestWcf" /> </service> </services> </system.serviceModel> </configuration>
而在Hosting宿主内的代码就精简了许多
using System; using System.ServiceModel; using System.ServiceModel.Description; using Contracts; using Services; namespace Hosting { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(TestWcfService))) { //host.AddServiceEndpoint(typeof(ITestWcf), new WSHttpBinding(), "http://127.0.0.1:9999/testwcfservice"); //if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) //{ // ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); ; // behavior.HttpGetEnabled = true; // behavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/testwcfservice/metadata"); // host.Description.Behaviors.Add(behavior); //} host.Opened += delegate { Console.WriteLine("CalculaorService已经启动,按任意键终止服务!"); }; host.Open(); Console.Read(); } } } }
一般对于初学者来说,WCF的配置显得过于复杂,直接对配置文件进行手工编辑不太现实。可以通过VS的工具(Tools)菜单,选择“WCF Service Configuration Editor”子项,开启这样的一个配置编辑器
客户端调用:在运行服务寄宿程序(Hosting.exe)的情况下,右键点击Client项目,在弹出的上下文菜单中选择“添加服务引用(Add Service References)”,如图6所示的添加服务引用的对话会显示出来。在地址栏上键入服务元数据发布的源地址:http://127.0.0.1:9999/testwcfservice/metadata,并指定一个命名空间,点击OK按钮,VS为为你生成一系列用于服务调用的代码和配置。
客户端代码如下:
using System; using Client.WcfTest; namespace Client { class Program { static void Main(string[] args) { using (TestWcfClient hw=new TestWcfClient()) { Console.WriteLine(hw.HelloWord()); } } } }
当然输出结果就不用贴出来了。
接下来看第二种方式——IIS进程寄宿
在原有项目的基础上,添加一个wcf应用程序项目
打开TestWcfService.svc添加
然后生成运行TestWcfService,生成部署包后发布IIS
Tag:这里的配置文件基本和上面的一样,但这里不需要配置终结点地址
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="metadataBehavior"> <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 --> <serviceMetadata httpGetEnabled="true"/> <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="metadataBehavior" name="Services.TestWcfService"> <endpoint binding="wsHttpBinding" contract="Contracts.ITestWcf" /> </service> </services> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> </system.webServer> </configuration>
通过访问http://192.168.0.1/TestWcfService.svc
如图
然后在客户端添加服务引用
客户端代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Client.TestWcf; namespace Client { class Program { static void Main(string[] args) { using (TestWcfClient test = new TestWcfClient()) { Console.WriteLine(test.HelloWord()); } } } }
在发布IIS时,可能会遇到
这样的问题,解决方法:找到配置文件所在文件夹,单击右键属性,切换到“安全”选项卡,将 IIS-IUSRS 用户组添加到安全列表中,并按需求赋予其权限(我赋予了修改的权限),更改后如下图:
查看 web.config 的安全权限,如果有此用户组的权限则说明成功,否则退回到根文件夹,打开“安全”选项卡,选中 IIS-IUSRS 用户组,点“高级”打开高级安全设置对话框,选中 IIS-IUSRS 用户组,点击“更改权限”,打开可编辑的高级安全设置对话框,把下图红色区域的复选按钮选上,
完成以上步骤,如果还不能解决问题,就在 IIS 中选中应用程序,修改应用程序域。(如果没有4.0相应的应用程序域,在vs2010命令提示符下运行aspnet_regiis.exe –i)