【架构之路之WCF全析(一)】--服务协定及消息模式

上周微软开发布会说.NET支持完全跨平台和并开放Core源码的新闻,让我们顿时感到.NET要迎来它的春天。虽然早在几年前.NET就能开发Android和IOS,但是这次的跨平台把Linux都放到了微软战略之中,以后的.NET Developer就可以使用Vs开发Linux应用了,Developer又有了新的选择,从微软的战略转型也可以看出互联网已经步入到了新的模式,以后不再是PC的时代,移动互联和云时代已经到来。

最近做项目时使用到了WCF,项目把数据层和程序层进行了分割,相互之间的数据传输使用的就是WCF,这次的项目是为英国银行Enumis做的一整套银行的系统,从业务上整体划分为e-Banking、Corporate Panel、Etam、e-Commerce它们整体上构成了这家银行的一个网上管理系统,其实这种网上系统跟中国的银行是很类似的,这些系统之间是通过相互之间提供数据或者接口来协同工作。

WCF全称是Windows Communication Fundation,提供了统一的,可用于建立安全、可靠地面向服务的应用的高效开发平台。WCF是基于属性的开发,它统一了各种分布式技术,也就是说它在应用程序和数据之间、应用程序与应用程序之间提供了一个桥梁,通过使用WCF来管理数据之间的互操作。这里说所的统一分布式技术说的是它把Windows中所有的通信技术做了整合封装,把它们都封装到了WCF架构里面,这样无论是采用何种通信方式只需要添加一个WCF服务接口,然后所有基于WCF的应用都可以互相通信,这样增强了程序之间的灵活性。

如上图,在不使用WCF的时候要想实现之间的互通信可能就需要使用不同的技术来实现,这样在开发的时候就会耗费大量的时间来整合封装通信模块,如果采用WCF就可以减少模块的封装,使用WCF的属性来定义不同的通信接口,这样不同的程序之间或者程序与数据之间就可以通过WCF解耦,使得不同的模块间只需要关注自己本身的服务即可。

WCF不但封装了相互之间的通信服务,而且还封装了安全性和事务性的模块,为应用之间提供更加安全及高效的事务管理。

WCF导图

在WCF配置节中有三个主要的数据,分别为消息、服务和终结点。三个数据中服务的概念包含的最广,一个WCF可以称作一个服务,它类似于一个dll,每一个service文件都会独立的生成一个服务,在使用服务的一方添加服务引用。其中的应用程序在调用服务时所发送的信息被称为一个消息,它是一个数据单元,和计算机网络中的消息是类似的,包括消息的正文和消息头。在应用程序一端想用调用服务就必须引用创建的服务,其实是在配置文件中添加一个服务的终结点,每个服务的引用可以理解为一个终结点,在终结点中会配置服务所在的地址,互相通信的方式(如Http、Tcp等),服务的消息定义。

WCF是基于属性开发的,也就是说可以通过对类和方法采用属性标记法来指明服务及消息。在定义一个WCF时可以使用两种服务协定类和接口,这两种服务协定在产生的效果上是相同的,但是建议使用接口的方式,有更好的扩展性,而且有助于保持服务协定不变,在服务的版本变更时只需要重新实现新接口即可。

一、服务协定

WCF创建服务时是通过使用属性来指明的,在接口或类的定义上方使用ServiceContract(服务契约)来指明一个服务,在方法定义上方使用OperationContract(方法契约)来指明一则消息。这样就完成了一个WCF的定义工作,如果使用的是接口那么需要实现相应的接口才可。具体的定义方法来看下面的示例,使用的是接口方式来定义服务契约。

1、添加一个WCF

添加一个WCF应用程序集,然后在程序集中添加一个WCF,在添加时Item时可以选择WCF Service这样Vs会根据自带的模板新增一个接口的服务协定,并添加一个新的svc文件来实现接口,这个svc文件就是对应的wcf的实现类。另外也可以手动的编写一个服务协定接口,并实现相应的方法。如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Contracts
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService2" in both code and config file together.
    [ServiceContract]
    public interface IService2
    {
        [OperationContract]
        string DoWork();
    }

    public class Service2 : IService2
    {
        public string DoWork()
        {
            return "Hello WCF!";
        }
    }

}

2、使用服务

想要使用服务,在程序集中有两种方式,一种是通过添加服务的方法添加指定的服务,另外也可以手动在配置文件中添加终结点来实现服务的添加,

选中添加服务引用然后会弹出如下图显示的服务添加的界面,在文本框中可以手动输入服务地址,同样也可以点击Discover让vs自动识别新添加的服务,如下图:

Note:添加完服务后一定要手动的生成新服务,否在在添加服务引用时会报错,显示没有找到该服务的方法。

添加完服务的引用后程序集就可以直接使用服务的方法,这种方法就好像是引入了一个新的dll文件一样,在使用时只需要引入命名空间,直接就可以调用服务,这里实现一个简单的Helloworld程序:

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

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            IService2 service = new Service2();
            Console.WriteLine(service.DoWork());
            Console.Read();
        }
    }
}

运行结构如下图所示:

二、消息模式

上节介绍了有关WCF的服务的创建方法,并做了一个小的Demo来演示WCF的创建过程,WCF是采用属性标注开发的,在定义时相当的简单。接下来我们对消息模式做详细的讨论。WCF提供了三种消息模式,分别是单向模式、请求/回答模式和双工模式,三种模式都支持客户端向服务端发送消息,不同的是单向模式只支持消息的发送,不支持返回。请求/回答模式支持客户端向服务端发送数据,并同时等待返回数据,它不支持服务端调用客户端。双工模式则比较强大,不仅支持客户端调用服务端的方法,同时也支持服务端调用客户端的方法,功能强大。

消息模式导图

1、单向模式

单向模式顾名思义是一种单向的请求,客户端向服务端发出消息请求后客户端就和服务端失去了联系,请求的一端不会关心是否返回结果继续往下执行。也就是说客户端发送请求后就会向下继续执行,不会等待服务端返回消息,而且服务端接收消息并执行服务,这种单向的模式其实是一种多线程下的操作,客户端发出消息后,客户端和服务端就会同时执行,这样它们之间就不会互相冲突,同时也是线程安全的,提高了执行效率。

单向模式只需要在方法声明中添加IsOneWay属性即可,它即可表示该消息的调用使用的是单向模式。如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService4
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {
        //声明单向模式消息的方法
        [OperationContract(IsOneWay = true)]
        void GetData();

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);

        // TODO: Add your service operations here
    }

    // Use a data contract as illustrated in the sample below to add composite types to service operations.
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

namespace WcfService4
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    //在一个service中实现WCF的接口协议
    public class Service1 : IService1
    {
        public void GetData()
        {
            System.Threading.Thread.Sleep(10000);
            Console.WriteLine("你好哈");
            //return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
    }
}

//在客户端调用该服务,结果该线程并不会停顿而是继续执行客户端中的方法。
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceReference1.IService1 service1=new Service1Client();
            service1.GetData();
            Console.WriteLine("This Main function");
            Console.Read();
        }
    }
}

上面的示例演示了单向模式的具体过程,在定义接口服务协议的时候为方法制定了IsOneWay属性,这时就会使该消息变成为单向的请求模式。客户端在调用服务的方法后,线程并没有停止请求,而是继续向下执行,这种请求方式就是单向模式。

2、请求/答复模式

这种模式是WCF消息模式的模式,也就是说客户端在服务端请求后会等待服务端执行完毕并返回给客户端数据后,客户端才会继续向下执行,这种方式相对单向模式来说灵活性差,但是安全性高,因为是单线程的所以安全性极高,适用于有数据返回的请求。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WcfService4
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IService1
    {
        //声明请求/答复模式消息的方法
        [OperationContract(IsOneWay = true)]
        string GetData();

    }

}

namespace WcfService4
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    //在一个service中实现WCF的接口协议
    public class Service1 : IService1
    {
        public string GetData()
        {
            System.Threading.Thread.Sleep(10000);
            Console.WriteLine("你好哈");
            return string.Format("You apply the WCF!");
        }
    }
}

//在客户端调用该服务,结果该线程会根据WCF消息线程的时间停顿,当停顿完成后才会继续向下执行。
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceReference1.IService1 service1=new Service1Client();
            service1.GetData();
            Console.WriteLine("This Main function");
            Console.Read();
        }
    }
}

3、双工模式

双工模式相交前两种模式来说相对复杂,它的请求方式同时适用于客户端和服务端,也就是说客户端可以请求服务端另外服务端也请求客户端,它们的调用关系是相互的,也就是客户端请求服务端的方法后,服务端同时请求客户端进行数据的交换这种方法就需要使用双工模式。

也就是说双工模式同时附加了服务端与客户端的通信机制。在定义双工模式时需要在服务端指定一个回调函数(使用CallBackContract属性)同时定义两个接口,一个是服务端的消息接口,另外一个是客户端需要实现的接口(即:服务端的回调方法)。服务端需要实现服务的接口,客户端需要实现客户端的服务协定接口。

定义双工服务,在定义时同时也要定义回调服务,也就是在客户端实现的服务,也就是说在声明服务时需要使用CallbackContract来指定回调的协定类,另外也要定义回话的模式,需要使用SessionMode.Required也就是必须使用回话的意思。具体定义方法如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Service
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract(SessionMode = SessionMode.Required,CallbackContract = typeof(ICallBack))]
    public interface IService1
    {
        [OperationContract]
        string ApplyData(int value);
    }

    public interface ICallBack
    {
        [OperationContract]
        string GetData(string data);
    }
}

定义完服务后接下来需要在服务端和客户端实现服务的协定,这里需要特别注意。双工协定下,如果客户端和服务端相互调用的话,就会产生链式的死循环,循环就会导致死锁所以需要在实现服务的一方使用ServiceBehaviorAttribute特性的ConcurrencyMode属性将并发模式设为Reentrant或者Multiple均可以解决这个问题。

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace Service
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class Service1 : IService1
    {
        public string ApplyData(int value)
        {
            ICallBack callBack = OperationContext.Current.GetCallbackChannel<ICallBack>();

            string strPrint=callBack.GetData("hahha");

            return string.Format("You applyed the data is:{0},we getted data is: {1}",strPrint, value);

        }

    }
}

实现客户端回调方法:

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            CallBack callBack=new CallBack();
            InstanceContext instanceContext=new InstanceContext(callBack);
            IService1 service1=new Service1Client(instanceContext);
            string strPrint=service1.ApplyData(32);
            Console.WriteLine(strPrint);
            Console.Read();
        }
    }

    public class CallBack : ServiceReference1.IService1Callback
    {
        public string GetData(string data)
        {
            return data;
        }
    }
}

打印结果:

双工协定相较前面两种实现起来会比较麻烦,所以在定义时需要有很多地方需要注意,这里介绍几种初学者需要注意的地方。

    Note1:绑定方式

在建立双工协定时一定要注意使用支持双工协定的绑定,默认的basicHttpBinding绑定方式并不支持双工协定,所以在客户端添加双工服务协定时就会出错,找不到协议定义的接口。可以使用wsDualHttpBinding绑定,在服务的终结点中声明绑定方法,绑定方法如下:

<endpoint address="" binding="wsDualHttpBinding" contract="Service.IService1">

    Note2:回调导致的死锁

上面的示例中使用的是请求/回复协定,也就是在服务发出后要等待服务执行的一方完成服务然后继续向下执行,但是上面的代码在运行后并没有出错,是因为在服务的实现一端使用了ServiceBehaviorAttribute属性指定了一种属性,如果不指定就会出现下面的错误:

这个错误出现就是因为服务在调用时出现了死锁(deadlock)的现象,因为客户端调用服务端的请求,然后服务端又调用客户端,这样继续下去就会导致恶性的循环,所以为了避免这种情况,需要在服务实现的一方使用ServiceBehaviorAttribute特性的ConcurrencyMode属性将并发模式设为Reentrant或者Multiple

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class CalculatorService : ICalculator
{
    //省略实现
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class CalculatorService : ICalculator
{
    //省略实现
}

结语

本系列文章主要是来快速的入门学习WCF的应用,所以有些地方讲的较详细,不需要的可以略过。本文主要从WCF的基础开始重点介绍了WCF的一些术语及WCF三种基本的消息模式,这三种模式个有自己的优缺点,在使用时要根据具体情况具体分析。

时间: 2024-12-17 04:23:51

【架构之路之WCF全析(一)】--服务协定及消息模式的相关文章

【WCF全析(一)】--服务协定及消息模式

上周微软开发布会说.NET支持完全跨平台和并开放Core源码的新闻,让我们顿时感到.NET要迎来它的春天.虽然早在几年前.NET就能开发Android和IOS,但是这次的跨平台把Linux都放到了微软战略之中,以后的.NET Developer就可以使用Vs开发Linux应用了,Developer又有了新的选择,从微软的战略转型也可以看出互联网已经步入到了新的模式,以后不再是PC的时代,移动互联和云时代已经到来. 最近做项目时使用到了WCF,项目把数据层和程序层进行了分割,相互之间的数据传输使用

WCF 设计和实现服务协定

WCF 术语:? 消息 – 消息是一个独立的数据单元,它可能由几个部分组成,包括消息正文和消息头.? 服务 – 服务是一个构造,它公开一个或多个终结点,其中每个终结点都公开一个或多个服务操作.? 终结点 – 终结点是用来发送或接收消息(或执行这两种操作)的构造. 终结点包括一个定义消息可以发送到的目的地的位置(地址).一个描述消息应如何发送的通信机制规范(绑定)以及对于可以在该位置发送或接收(或两者皆可)的一组消息的定义(服务协定)- 该定义还描述了可以发送何种消息. – WCF 服务作为一个终

WCF 设计和实现服务协定(01)

作者:jiankunking 出处:http://blog.csdn.net/jiankunking WCF 术语: ? 消息 – 消息是一个独立的数据单元,它可能由几个部分组成,包含消息正文和消息头.? 服务 – 服务是一个构造.它公开一个或多个终结点.当中每一个终结点都公开一个或多个服务操作.? 终结点 – 终结点是用来发送或接收消息(或执行这两种操作)的构造. 终结点包含一个定义消息能够发送到的目的地的位置(地址).一个描写叙述消息应怎样发送的通信机制规范(绑定)以及对于能够在该位置发送或

菜鸟眼中的WCF(2)—服务协定

在上一篇文章中简单的对WCF进行了讲解并做了一个简单的实例,那么今天就继续对它进行解析--服务协定的初探. 说到协定大家肯定不陌生,只要参加了工作就一定会签订各种协定,比如合同的签订,我们就是其中的一方,按着这个双方签订的合同来工作,它授予你什么权限,你就有什么权限,不能做本职外的工作.各位想一想这个合同的协议,像不像我们这里说的服务协定?是啊,服务协定其实没啥了不起的,刚才签下合作协议的个人和公司分别叫做"客户端"和"服务器". 服务协定告诉客户端,哪些方法你可以

【WCF全析(二)】--服务配置部署详解

上篇文章主要讨论了WCF的基本内容,其中包括WCF的术语.创建方法及WCF在开发过程中使用的意义,它不仅能够提供程序之间的通信,而且还能提供程序和数据间的通信,WCF提供了多样化的程序之间的通信,不仅支持App的通信而且还支持web与应用程序之间的通信,可谓是功能强大.虽然上文讨论了WCF的基本使用方法,并做了很多Demo,但是都只是关于WCF的创建和调用的,今天来看看WCF的配置方法. WCF 配置导图 上图整理了服务配置过程中所用到的基本的元素,大致的步骤主要是首先要在调用服务的程序集中添加

我们一起学习WCF 第五篇数据协定和消息协定(附上源码)

A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或返回类型精确定义为进行交换而序列化哪些数据(将哪些数据转换为 XML)摘自MSDN)也就说数据协定是客户端和服务端之间达成的数据协议,相互通信的参数会被序列化然后进行传输.那么我用图来表示为什么用数据协定. 下面用图来说明其几个用处 那么下面我们来看看数据协定的代码实现 1:创建一个协定类 1 [D

京东618:商城交易平台的高可用架构之路

据腾讯科技报道,6月18日零点,京东全民年中购物节拉开了高潮的序幕.第一个小时的销售额超过去年同期的250%.从凌晨开始的海量订单让6月1日就拉开序幕的京东年中购物节奏出最强音,大量用户瞬间涌入,峰值订单被不断刷新.为了应对如此大规模的流量增长,京东研发团队几乎全年都在高筑墙.广积粮,一直着力从技术层面为用户提供流畅的交易体验,以保证在峰值交易时期系统的高可用性.在京东整个电商体系中,交易系统占据着其中的半壁江山,购物车.结算.库存.价格等相关的环节都包含在其中,可以说交易系统的高可用能力基本上

从经典架构项目中透析微服务架构的核心概念和充血模型

微服务架构和SOA区别 微服务现在辣么火,业界流行的对比的却都是所谓的Monolithic单体应用,而大量的系统在十几年前都是已经是分布式系统了,那么微服务作为新的理念和原来的分布式系统,或者说SOA(面向服务架构)是什么区别呢? 我们先看相同点: 需要Registry,实现动态的服务注册发现机制:需要考虑分布式下面的事务一致性,CAP原则下,两段式提交不能保证性能,事务补偿机制需要考虑:同步调用还是异步消息传递,如何保证消息可靠性?SOA由ESB来集成所有的消息:都需要统一的Gateway来汇

【Hibernate步步为营】--核心对象+持久对象全析(二)

上篇文章讨论了Hibernate的核心对象,在开发过程中经常用到的有JTA.SessionFactory.Session.JDBC,其中SessionFactory可以看做数据库的镜像,使用它能够创建Session对象,JTA用来管理事务,在对象模型修改后同步到数据库中,另外还有Hibernate作为持久层它封装了持久层的转化过程,下面着重讨论持久对象的转换过程. 一.状态解析 Hibernate的持久对象主要分为三个状态,Transient.Persistent.Detached,其中Tran