寄宿于CS程序的WCF服务

最近项目中,需要对外部程序提供服务接口,用来进行数据交互和部分设备控制。由于都是使用的.NET平台开发的,因此想到使用WCF服务。之前也用过WCF服务,但是当初使用的时候是通过IIS寄宿的,有些地方不太让人满意,一则是同一个软件要部署两个地方,CS的桌面程序和寄宿于IIS的WCF服务部分,二则是由于系统本身问题,使用的是SQLite数据库,无法实现多线程访问,造成了数据重复,容易造成数据不一致。所以现在准备把WCF服务寄宿于CS程序中,这样就解决了以上两个问题。

由于对WCF一知半解,只知道按部就班的使用,从明白过其中的道理,所以在网上找了些教程[1],实现了自己的想法,但其中碰到不少问题,想来还是记下,或许以后还有用处。

本文使用一个最简单的控制台应用程序,同时通过使用WcfTestClient.exe测试,来完成这个示例。

一、在代码中实现并配置WCF服务。

在VS2012中创建一个控制台应用程序项目CsWcf,并添加接口ICalculator作为契约接口、类CalculatorService作为服务实现此接口中的操作方法,代码如下:

1. ICalculator.cs--服务契约

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.ServiceModel;
   6:  
   7: namespace CsWcf
   8: {
   9:     [ServiceContract]
  10:     public interface ICalculator
  11:     {
  12:         [OperationContract]
  13:         double Add(double x, double y);
  14:     }
  15: }

2. CalculatorService.cs--服务实现

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.ServiceModel;
   6:  
   7: namespace CsWcf
   8: {
   9:     public class CalculatorService:ICalculator
  10:     {
  11:         public double Add(double x, double y)
  12:         {
  13:             return x + y;
  14:         }
  15:     }
  16: }

3. 在Program.cs中的Main函数中,添加如下代码,实现WCF服务的寄宿,并开启服务。

   1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
   2: {
   3:     host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://192.168.1.102:10002/CalculatorService");
   4:  
   5:     if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
   6:     {
   7:         ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
   8:         behavior.HttpGetEnabled = true;
   9:         behavior.HttpGetUrl = new Uri("http://192.168.1.102:10002/CalculatorService");
  10:         host.Description.Behaviors.Add(behavior);
  11:     }
  12:  
  13:     host.Opened += delegate
  14:     {
  15:         Console.WriteLine("CalculaorService已经启动,按任意键终止服务!");
  16:     };
  17:  
  18:     host.Open();
  19:     Console.Read();
  20: }

4. F5调试执行,服务开启后,打开WcfTestClient,添加服务地址,可以正确调用Add服务函数。

但是,以上将服务相关配置写到代码中了,这不利于后面的安装和部署。所以需要将配置信息放置在config配置文件中。

二,使用配置文件动态配置WCF服务

配置app.config文件,实现WCF服务的可配置性。在项目中添加应用程序配置文件,并添加以下内容:

   1: <system.serviceModel>
   2:   <behaviors>
   3:     <serviceBehaviors>
   4:       <behavior name="metadataBehavior">
   5:         <serviceMetadata httpGetEnabled="true" httpGetUrl="http://192.168.1.102:10002/CalculatorService/metadata" />
   6:       </behavior>
   7:     </serviceBehaviors>
   8:   </behaviors>
   9:   <services>
  10:     <service behaviorConfiguration="metadataBehavior" name="CsWcf.CalculatorService">
  11:       <endpoint address="http://192.168.1.102:10002/calculatorservice" binding="wsHttpBinding" 
  12:                 contract="CsWcf.ICalculator"  />
  13:       <endpoint address="http://192.168.1.102:10002/calculatorservice/MEX/" binding="mexHttpBinding" 
  14:                   contract="IMetadataExchange"  />
  15:     </service>
  16:   </services>
  17: </system.serviceModel>

同时需要删除Program.cs中的配置代码:

   1: using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
   2: {
   3:     host.Opened += delegate
   4:     {
   5:         Console.WriteLine("CalculaorService已经启动,按任意键终止服务!");
   6:     };
   7:  
   8:     host.Open();
   9:     Console.Read();
  10: }

F5调试执行,与刚刚的执行结果一样!此处要特别注意:配置节中的第二个endpoint,即MEX配置,一定要加上,否则会出现如下错误:

错误: 无法从 http://192.168.1.102:10002/CalculatorService 获取元数据如果是您有权访问的 Windows (R) Communication Foundation 服务,请检查是否已启用在指定地址发布元数据。有关启用元数据发布的帮助,请参阅 http://go.microsoft.com/fwlink/?LinkId=65455 上的 MSDN 文档。WS-Metadata Exchange 错误 URI: http://192.168.1.102:10002/CalculatorService 元数据包含无法解析的引用:“http://192.168.1.102:10002/CalculatorService”。 Sendera:BadContextToken无法处理消息。这很可能是因为操作“http://schemas.xmlsoap.org/ws/2004/09/transfer/Get”不正确,或因为消息包含无效或过期的安全上下文令牌,或因为绑定之间出现不匹配。如果由于未处于活动状态导致服务中止了该通道,则安全上下文令牌无效。若要防止服务永久中止闲置会话,请增加服务终结点绑定上的接收超时。HTTP GET Error URI: http://192.168.1.102:10002/CalculatorService 下载“http://192.168.1.102:10002/CalculatorService”时出错。 请求因 HTTP 状态 400 失败: Bad Request。

我在Artech的文章[1]中学习中并没有看到第二个终结点的配置,所以运行的时候一直出错,找了好久才找到这个解决办法,可以参考“WCF Part 4 : Make your service visible through metadata”这篇文章[2]

三、其它机器访问权限限制的解决办法

以上两步骤,我们完成了WCF服务的寄宿、发布和访问,但是如果在其它计算机上访问此WCF服务时,会发现权限提示:

无法满足对安全令牌的请求,因为身份验证失败!

这个时候,默认的安全是计算机名和用户名做为权限要求。如果想让其他用户也可以随时访问到些WCF服务,就需要修改配置文件中的安全级别,设置<security>的mode为None就可以了。同时更改一个endpoint的bindingConfiguration="wsHttpBindingConfiguration"。

   1: <bindings>
   2:   <wsHttpBinding>
   3:     <binding name="wsHttpBindingConfiguration" maxReceivedMessageSize="20971510">
   4:       <readerQuotas maxStringContentLength="20971520" maxArrayLength="20971520"/>
   5:       <security mode="None"/>
   6:     </binding>
   7:   </wsHttpBinding>
   8: </bindings>

再次运行此服务,其它计算机上也可以访问此服务了。

总结:WCF用起来简单,“制作”起来貌似也很简单,和写其它的代码基本无异,但是真正使用起来的时候,却又经常碰到这样那样的问题,个人感觉WCF是一个极其精密的仪器,操作简单,但是仪器的操作步骤和顺序却比较麻烦,而且零部件不牢固,经常脱落损坏,所以要想更好的使用它,需要对它有个很好的了解才是。由于现在网络的存在,好多东西都是用的时候搜索一下,基本没有系统、深入的学习过,这对以后的学习和工作经验的积累都用处不太大。

[1] Artech, 我的WCF之旅(1):创建一个简单的WCF程序

[2] Dennis van der Stelt, WCF Part 4 : Make your service visible through metadata

posted @ 2013-03-02 18:16  Ritchie(乞戈)  阅读(4348)  评论(4编辑  收藏  举报