本文的WCF服务应用功能很简单,却涵盖了一个完整WCF应用的基本结构。希望本文能对那些准备开始学习WCF的初学者提供一些帮助。

在这个例子中,我们将实现一个简单的计算器和传统的分布式通信框架一样,WCF本质上提供一个跨进程、跨机器、跨网络的服务调用。在本例中,客户端和WCF应用服务通过运行在同一台机器上的不同进程模拟。

步骤一、构建整个解决方案

    1.创建一个空白的解决方案

      

  2.添加四个项目和引用及关系

      

   Service.Interface  用于定义服务契约的类库项目,引用WCF核心程序集System.ServuceModel.dll
              Service           用于定义服务类型的类库项目,由于服务类型需要实现定义在ervice.Interface中相应的接口,因此需要引用Service.Interface
              Hosting           作为服务寄主的控制台应用,该项目同时引用Service.Interface、System.ServuceModel.dll、Service
              Client           模拟服务的客服端控制台应用  该醒目引用System.ServuceModel.dll

      

     

步骤二、创建服务契约(一般将服务契约定义为接口)

    WCF采用基于接口(MSDN上翻译为:服务协定)的交互方式实现了服务功能,以及客户端和服务端之间的松耦合。WCF包含五种类型的协定:服务协定、操作协定、消息协定、错误协定和数据协定。

从功能上讲,服务协定将多个相关的操作联系在一起,组成单个功能单元。协定可以定义服务级设置,如服务的命名空间、对应的回调协定以及其他此类设置,以及各种操作。

从消息交换的角度来讲,服务协定则定义了基于服务调用的消息交换过程中, 请求消息和回复消息的结构,以及采用的消息交换模式。

从使用编程语言的角度来讲,协定是通过所选的编程语言创建一个接口,然后将 ServiceContractAttribute 属性应用于该接口。通过实现该接口,可生成实际的服务代码。

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.ServiceModel;

 namespace Service.Interface
 {
     /// <summary>
     /// 计算器
     /// </summary>
     [ServiceContract(Name = "CalculatorService",Namespace="http://www.artech.com/")]
     public interface ICalculator
     {
         /// <summary>
         /// 加
         /// </summary>
         /// <param name="x"></param>
         /// <param name="y"></param>
         /// <returns></returns>
         [OperationContract]
         double Add(double x,double y);

         /// <summary>
         /// 减
         /// </summary>
         /// <param name="x"></param>
         /// <param name="y"></param>
         /// <returns></returns>
         [OperationContract]
         double Subtract(double x,double y);

         /// <summary>
         /// 乘
         /// </summary>
         /// <param name="x"></param>
         /// <param name="y"></param>
         /// <returns></returns>
         [OperationContract]
         double Multiply(double x,double y);

         /// <summary>
         /// 除
         /// </summary>
         /// <param name="x"></param>
         /// <param name="y"></param>
         /// <returns></returns>
         [OperationContract]
         double Divide(double x,double y);
     }
 }

步骤三、实现WCF服务契约

  

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Service.Interface;

 namespace Service
 {
     public class CalculatorService:ICalculator
     {

         public double Add(double x, double y)
         {
             return x + y;
         }

         public double Subtract(double x, double y)
         {
             return x - y;
         }

         public double Multiply(double x, double y)
         {
             return x * y;
         }

         public double Divide(double x, double y)
         {
             return x / y;
         }
     }
 }

步骤四、通过自我寄宿的方式寄宿服务

   WCF服务需要依存一个运行着的进程(宿主),服务寄宿就是为服务指定一个宿主的过程。WCF是一个基于消息的通信框架,采用基于终结点(Endpoint)的通信手段。

终结点主要由地址(Address)、绑定(Binding)和协定(Contract)三要素组成,如图所示。由于三要素应为首字母分别为ABC,所以就有了易于记忆的公式:Endpoint = ABC。一个终结包含了实现通信所必需的所有信息。如下图。

终结点三要素

  • 地址(Address):一个指示可以查找终结点的位置的地址。地址决定了服务的位置,解决了服务寻址的问题
  • 绑定(Binding):一个指定客户端如何与终结点进行通信的绑定。绑定实现了通信的所有细节,包括网络传输、消息编码,以及其他为实现某种功能(比如安全、可靠传输、事务等)对消息进行的相应处理。WCF中具有一系列的系统定义绑定,比如BasicHttpBinding、WsHttpBinding、NetTcpBinding等,
  • 协定(Contract):一个标识可用操作的协定。协定是对服务操作的抽象,也是对消息交换模式以及消息结构的定义。
  • 行为(Behavior):一组指定终结点的本地实现细节的行为。

服务寄宿的目的就是开启一个进程,为WCF服务应用提供一个运行的环境。通过为服务添加一个或多个终结点,使之暴露给潜在的服务调用者。服务调用者最终通过相匹配的终结点对该服务进行调用。

一)代码方式实现寄宿

        using Service;
             using Service.Interface;
             using System.ServiceModel;
             using System.ServiceModel.Description;

             namespace Hosting
             {
                 class Program
                 {
                     static void Main(string[] args)
                     {
                         //在进行真正的开放时一般在配置文件里面进行配置添加终结点和服务行为的定义
                         using(ServiceHost host = new ServiceHost(typeof(CalculatorService)))
                         {
                             //指定绑定和总结点的地址
                             host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:3721/calculatorservice");
                             //数据的发布
                             if(host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                             {
                                 //创建服务行为
                                 ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                                 //是否发布元数据以便使用HTTPS/GET请求进行检索
                                 behavior.HttpGetEnabled = true;
                                 //使用HTTPS/GET请求的元数据发布的位置
                                 behavior.HttpGetUrl = new Uri("http://127.0.0.1:3721/calculatorservice/metadata");
                                 //添加到发布上
                                 host.Description.Behaviors.Add(behavior);
                             }
                             host.Opened += delegate
                             {
                                 Console.WriteLine("CalculatorService已经启动,按任意键终止服务!");
                             };
                             //通讯状态转换到已打开
                             host.Open();
                             Console.ReadLine();
                         }
                     }
                 }
             }

  1) WCF服务寄宿通过一个特殊的对象完成:ServiceHost。在上面的代码基本实现的功能说明,基于WCF服务应用的类型(typeof(CalculatorService))创建了ServieHost对象,并添加了一个终结点。具体的地址为http://127.0.0.1:3721/calculatorservice/metadata,采用了WSHttpBinding,并指定了服务协定的类型IBookService。

2) 松耦合是SOA的一个基本的特征,WCF服务应用中客户端和服务端的松耦合体现在客户端只需要了解WCF服务基本的描述,而无需知道具体的实现细节,就可以实现正常的WCF服务调用。WCF服务的描述通过元数据(Metadata)的形式发布出来。WCF中元数据的发布通过一个特殊的服务行为ServiceMetadataBehavior实现。在上面提供的服务寄宿代码中,我们为创建的ServiceHost添加了ServiceMetadataBehavior,并采用了基于HTTP-GET的元数据获取方式,元数据的发布地址通过ServiceMetadataBehavior的HttpGetUrl指定。在调用ServiceHost的Open方法对服务成功寄宿后,我们可以通过该地址获取服务相关的元数据。

3) 运行已经生成的hosting.exe,

  4)然后在浏览器地址栏上键入http://127.0.0.1:3721/calculatorservice/metadata,你将会得到以WSDL形式体现的服务元数据,如下图所示。

二)配置文件方式实现寄宿

在实际应用中,对于WCF应用服务的寄宿,一般不会直接通过编码的方式进行终结点的添加和服务行为的定义,而是通过写配置文件的方式实现,这样可以方便修改。

1)  现在我在Hosting项目中添加一个app.config配置文件,把下面的配置信息添加到配置文件app.config中。

    

 <?xml version="1.0" encoding="utf-8" ?>
 <configuration>
     <startup>
         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
     </startup>
   <system.serviceModel>

     <behaviors>
       <serviceBehaviors>
         <behavior name="metadataBehavior">
           <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3721/calculatorservice/metadata" />
         </behavior>
       </serviceBehaviors>
     </behaviors> 

     <services>
       <service  behaviorConfiguration="metadataBehavior" name="Service.CalculatorService">
         <endpoint address="http://127.0.0.1:3721/calculatorservice"
             binding="wsHttpBinding" bindingConfiguration="" contract="Service.Interface.ICalculator" />
       </service>
     </services>

   </system.serviceModel>
 </configuration>

  2)  增加app.config配置文件与配置信息之后,我们原来写的寄宿代码就不能使用了,需要进行服务寄宿代码的修改,而且代码会变的更简洁,只需几行代码就可以了。代码如下。

  

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Service;
 using Service.Interface;
 using System.ServiceModel;
 using System.ServiceModel.Description;

 namespace Hosting
 {
     class Program
     {
         static void Main(string[] args)
         {
             using(ServiceHost host = new ServiceHost(typeof(CalculatorService)))
             {
                 ////指定绑定和终结点的地址
                 //host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:3721/calculatorService");
                 ////数据的发布
                 //if(host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
                 //{
                 //    //创建服务行为
                 //    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                 //    //是否发布元数据以便使用HTTPS/GET请求进行检索
                 //    behavior.HttpGetEnabled = true;
                 //    //使用HTTPS/GET请求的元数据发布的位置
                 //    behavior.HttpGetUrl = new Uri("http://127.0.0.1:3721/calculatorService/metadata");
                 //    //添加到发布上
                 //    host.Description.Behaviors.Add(behavior);
                 //}
                 host.Opened += delegate
                 {
                     Console.WriteLine("CalculatorService已经启动,按任意键终止服务!");
                 };
                 //通讯状态转换到已打开
                 host.Open();
                 Console.ReadLine();
             }
         }
     }
 }

   3) 执行hosting.exe应用程序,结果如下图。

  

下一章节讲怎么通过客户端去调用我们成功寄宿后的服务 (欢迎关注)

WCF学习——构建一个简单的WCF应用(一)的更多相关文章

  1. WCF学习——构建一个简单的WCF应用(二)

    我们接着上一篇文章进行讲解 http://www.cnblogs.com/songjianhui/p/7060698.html 一:客户端通过添加引用调用服务 WCF应用服务被成功寄宿后,WCF服务应 ...

  2. 学习构建一个简单的wcf服务

    入门,构建第一个WCF程序 1.服务端 建立一个控制台应用程序作为Server,新建一个接口IData作为服务契约.这个契约接口一会儿也要放到Client端,这样双方才能遵循相同的标准.别忘了添加对 ...

  3. 重温WCF之构建一个简单的WCF(一)(2)通过Windows Service寄宿服务和WCF中实现操作重载

    参考地址:http://www.cnblogs.com/zhili/p/4039111.html 一.如何在Windows Services中寄宿WCF服务 第一步:创建Windows 服务项目,具体 ...

  4. 重温WCF之构建一个简单的WCF(一)(1)通过控制台和IIS寄宿服务

    一.理解什么是WCFWCF就是.NET平台下各种分布式技术的集成,并提供了一套统一的编程接口 二.WCF的定义WCF(Windows Communication Foundation)是微软为构建面向 ...

  5. 构建一个简单的WCF应用——WCF学习笔记(1)

    通过<WCF全面解析>来知识分享....感谢蒋金楠老师@Artech 一.VS中构建解决方案   Client一个控制台程序模拟的客户端,引用Service.ServiceModel.dl ...

  6. [WCF学习笔记] 我的WCF之旅(1):创建一个简单的WCF程序

    近日学习WCF,找了很多资料,终于找到了Artech这个不错的系列.希望能从中有所收获. 本文用于记录在学习和实践WCF过程中遇到的各种基础问题以及解决方法,以供日后回顾翻阅.可能这些问题都很基础,可 ...

  7. WCF入门, 到创建一个简单的WCF应用程序

    什么是WCF?  WCF, 英文全称(windows Communication Foundation) , 即为windows通讯平台. windows想到这里大家都知道了 , WCF也正是由微软公 ...

  8. 【Android Developers Training】 3. 构建一个简单UI

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. gRPC初探——概念介绍以及如何构建一个简单的gRPC服务

    目录 引言 1. gRPC简介 2. 使用Protocol Buffers进行服务定义 2.1 定义消息 2.2 定义服务接口 3.构建简单的gRPC服务 3.1 编写proto文件,定义消息和接口 ...

随机推荐

  1. Linux学习之竿头直上

    今天第二讲昨天我们讲解了10基础命令,今早上我继续为大家讲解10个linux常见命令 今天主要讲解与网络相关的命令和软件安装的命名 NetworkManager 与rpm 在windows中我们查看网 ...

  2. TP5学习基础一:增删改查小demo

    ①TP5--增删改查简单的demo 我先吐槽一下:因为工作需要研究tp5,去官网看了一下哎呦,资源挺多挺全啊!然后下载唯一免费的官方教程,我曹pdf打开533页.讲的很细但是开发能等看完才做吗?看到精 ...

  3. js与juery基础知识对比(一)---2017-05-06

    用表格做的,想要对比的内容一目了然,红色部分为重点   js jquery 取元素 id: document.getElementById("aa"); 取到的是dom对象 cla ...

  4. 成熟的C#网络通信框架介绍——ESFramework通信框架

    (转自:http://www.cnblogs.com/zhuweisky/archive/2010/08/12/1798211.html) ESFramework通信框架是一套性能卓越.稳定可靠.强大 ...

  5. 记录——时间轮定时器(lua 实现)

    很长一段时间里,我错误的认识了定时器.无意中,我发现了“时间轮”这个名词,让我对定时器有了新的看法. 我错误的认为,定时器只需要一个 tick 队列,按指定的时间周期遍历队列,检查 tick 倒计时满 ...

  6. Android 真机无线调试

    有很多人在学Android的时候最开始接触的都是模拟机的测试,如果像好的模拟机比如genimotion,次一点的蓝手指,测试都还比较可以.有的也不缺乏是用真机测试.本人开始用华为真机测试,也是一直连线 ...

  7. Servlet路径映射

    Serlvlet路径映射 当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url. 容器默认请求的是一个Servlet,所以不会直接根据 ...

  8. swift学习 - 分类(Extensions)

    在oc中为了增强已有类的功能,我们经常使用分类.使用分类,我们可以在不破坏原有类的结构的前提下,对原有类进行模块化的扩展. 但是在swift中没有分类这种写法了.相对应的是swift中只有扩展(Ext ...

  9. 面试(3)-java-se-java中的匿名内部类总结

    java中的匿名内部类总结 匿名内部类也就是没有名字的内部类 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口 实例1 ...

  10. Java读写Excel之POI超入门

    转自:http://rensanning.iteye.com/blog/1538591 Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给J ...