我的WCF之旅(5):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的重载(Overloading)

简介:

对于.NET重载(Overloading)——定义不同参数列表的同名方法(顺便提一下,我们但可以在参数列表上重载方法,我们甚至可以在返回类型层面来重载我们需要的方法——页就是说,我们可以定义两个具有相同参数列表但不同返回值类型的两个同名的方法。不过这种广义的Overloading不被我们主流的.NET 语言所支持的——C#, VB.NET, 但是对于IL来说,这这种基于返回值类型的Overloading是支持的)。相信大家听得耳朵都要起老茧了。我想大家也清楚在编写传统的XML Web Service的时候,Overloading是不被支持的。

原因很简单,当我们用某种支持.NET的高级语言写成的程序被相应的编译器编译成Assembly的过程中,不单单是我们的Source Code会被变成IL Code,在Assembly中还会生成相应的原数据Metadata——这些Metadata 可以被看看是一张张的Table。这些Table存储了定义了主要3个方面的信息——构成这个Assembly文件的信息;在Assembly中定义的Type及其相关成员的信息;本引用的Assembly 及Type的信息。这些完备的Metadata成就了Assembly的自描述性(Self-Describing),也只是有了这些Metadata,使.NET可以很容易地根据方法参数的列表甚至是返回值得类型来判断调用的究竟了那个方法。

而对于XML Web Service,它的标准实际上是基于XML的,近一步说,一个XML Web Service是通过一个一段XML来描述的,而这个描述XML Web Service的XML,我们称之为WSDL(Web Service Description Language)。在WSDL中,Web Service的一个方法(Method)对应的是一个操作(Operation),Web Service 所有的Operation定义在WSDL中的portType Section。我们可以参照下面一段XML,它是从一个完整的WSDL中截取下来的。我们可以看到,portType包含了Web Service定义的所有Operation,每个Operation由一个operation XML Element表示。看过我前面Blog的读者应该知道,从消息交换(Message Exchange)的层面上讲,一个Operation实际上体现的是一种消息交换的模式(Message Exchange Pattern——MEP)。所以我们完全可以通过一定消息交换的输入消息(Input Message)和输出(Output Message )定义一个Operation。而WSDL也是这样做的。(这里顺便提一下,Output Message部仅仅对应一个方法的Return Value,还包括表明ref 和out的Parameter)。除了定义进行消息交互的Message的格式(一般通过XSD)之外,每个Operation还应该具有一个能够为一标识该Operation的ID,这个ID通过name XML Attribute来定义。通常的情况下,Operation的Name使用Web Service的方法名——这就是在传统XML Web Service不可以使用Overloading的原因。

< wsdl:portType  name ="ICalculator" >
   < wsdl:operation  name ="AddWithTwoOperands" >
     < wsdl:input  wsaw:Action ="http://tempuri.org/ICalculator/AddWithTwoOperands"  message ="tns:ICalculator_AddWithTwoOperands_InputMessage"   />
     < wsdl:output  wsaw:Action ="http://tempuri.org/ICalculator/AddWithTwoOperandsResponse"  message ="tns:ICalculator_AddWithTwoOperands_OutputMessage"   />
   </ wsdl:operation >
   < wsdl:operation  name ="AddWithThreeOperands" >
     < wsdl:input  wsaw:Action ="http://tempuri.org/ICalculator/AddWithThreeOperands"  message ="tns:ICalculator_AddWithThreeOperands_InputMessage"   />
     < wsdl:output  wsaw:Action ="http://tempuri.org/ICalculator/AddWithThreeOperandsResponse"  message ="tns:ICalculator_AddWithThreeOperands_OutputMessage"   />
   </ wsdl:operation >
</ wsdl:portType >

和XML Web Service,WCF也面临一样的问题——我觉得我们可以把WCF看成.NET平台下新一代的Web Service。虽然现有XML Web Service现在具有广泛的使用——尤其在构建跨平台性的分布是应用和进行系统集成上面,但是从Microsoft已经明确提出WSE 3.0将是最后一个Version的WSE,所以,现有的Web Service将会全面的过渡到WCF。WCF到底是什么东西,我在前面的文章中不断地提出这个问题,在这里我们从 另外一个方面来看待WCF。我们知道W3C定义了一系列关于WS的规范Specification,成为WS-* Specification。这一系列的Specification定义了建立在XML和SOAP标准之上的基于如何将一个可互操作系统(Interoperable System)的各个方面的标准,比如WS-Messaging,WS-Security,WS-Transaction等等。而WCF则可以看成是这一整套Specification的实现。但是这种实现最终还是落实到我们.NET编程上。我们可以把WS-Specification和我们的基于.NET语言的编程看成是两种截然不同的编程模型(Programming Model)。WCF的功能则是把这两种不同的编程模型统一起来,实现他们之间的一个Mapping——可以把WCF看成一个Adapter。

回到我们的Overloading上面来,Overloading是.NET Framework原生支持的。通过Overloading,我们可以使用同名的方法来定义不同的操作,从而使我们的Code显得更加优雅(Elegant)。要是Overloading在WCF中可以使用,WCF必须提供这样的一个Mapping——是被重载的具有相同方法的的方法Mapping到不同的Operation上。而提供着一个功能的就是ServiceContract。下面我们来结合一个Sample来看如何在WCF中使用Overloading。

沿用我们的Calculator的应用,现在我们做一个加法器,它具有两个Operation——两书相加和三数相加。这两个方法都用一个名称Add。

1.下面是Solution的结构。不像前面的结构,这这里我们没有把Service Contract单独提取出来,供Client和Service供用。因为我们现在模拟的是,Service完全由一个外部的第三方提供,Service 已经确定,不能根据Client的具体要求来修改Service。Source Code从这里下载。


2.Service端的Code:

Service Contract: Artech.OverloadableContract.Service ICalculator.cs.

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace Artech.OverloadableContract.Service
{
    [ServiceContract]
   public interface ICalculator
    {
        [OperationContract(Name = "AddWithTwoOperands")]
       double Add(double x, double y);

       [OperationContract(Name = "AddWithThreeOperands")]
       double Add(double x, double y, double z);
    }

}

这个Service Contract定义了Overloading的两个Add方法,为了把这两个方法映射到两个不同的Operation,我们通过System.ServiceModel.OperationAttribute 的Name属性为Operation指定一个Name——AddWithTwoOperands 和AddWithThreeOperands。

下面是Service的Code,简单地实现了Service Conract,无须赘言。

using System;
using System.Collections.Generic;
using System.Text;

namespace Artech.OverloadableContract.Service
{
    public class CalculatorService:ICalculator
    {
        ICalculator Members
    }

}

3.Hosting Service

App.config

<? xml version="1.0" encoding="utf-8"  ?>
< configuration >
     < system .serviceModel >
      
         < behaviors >
             < serviceBehaviors >
                 < behavior  name ="calculatorServiceBehavior" >
                     < serviceMetadata  httpGetEnabled ="true"   />
                 </ behavior >
             </ serviceBehaviors >
         </ behaviors >
      
         < services >
             < service  behaviorConfiguration ="calculatorServiceBehavior"  name ="Artech.OverloadableContract.Service.CalculatorService" >
                 < endpoint  binding ="basicHttpBinding"  contract ="Artech.OverloadableContract.Service.ICalculator"   />
                 < host >
                     < baseAddresses >
                         < add  baseAddress ="http://localhost:1234/calcuator"   />
                     </ baseAddresses >
                 </ host >
             </ service >
         </ services >
     </ system.serviceModel >
</ configuration >

Program.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using Artech.OverloadableContract.Service;

namespace Artech.OverloadableContract.Hosting
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
            {
                host.Open();
                Console.WriteLine("Calculator service has begun to listen ");
                Console.Read();
            }

        }

    }

}

相关的已经在前面的文章中说过,代码很简单,没有什么好说的。

现在我们来启动这个Host,在IE中通过键入这个地址http://localhost:1234/calcuator?wsdl看看生成的WSDL是什么样子。

通过截图我们可以看到,在WSDL的portType Section,两个Operation的Name已经成功地变成了我们在OperationContract Attrbute中指定的那样。


4.接下来我们为Client端添加一个Server Reference。就像在使用XML Web Service中添加Web Reference一样,添加Server Reference会为Client添加相应的客户端代码——倒入的Service Contract,继承自ClientBase<T>的Proxy Class, 和相应的Confugration。下面我们来分析这些通过添加Service Reference而生成的Code。

Imported Service Contract:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Artech.OverloadableContract.Client.CalculatorService.ICalculator")]
     public  interface ICalculator
     {
        
        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ICalculator/AddWithTwoOperands", ReplyAction="http://tempuri.org/ICalculator/AddWithTwoOperandsResponse")]
        double AddWithTwoOperands(double x, double y);
        
        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ICalculator/AddWithThreeOperands", ReplyAction="http://tempuri.org/ICalculator/AddWithThreeOperandsResponse")]
        double AddWithThreeOperands(double x, double y, double z);
    }

    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
     public  interface ICalculatorChannel : Artech.OverloadableContract.Client.CalculatorService.ICalculator, System.ServiceModel.IClientChannel
     {
}

我们可以看到这个Service Contract已经不是Service端的Contract了,Overloading方法已经被换成了与Oper阿tion Name相匹配的方法了。我们再看看Proxy Class:

[System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
     public partial  class CalculatorClient : System.ServiceModel.ClientBase<Artech.OverloadableContract.Client.CalculatorService.ICalculator>, Artech.OverloadableContract.Client.CalculatorService.ICalculator
     {
        
        public CalculatorClient()
        {
        }

        
        public CalculatorClient(string endpointConfigurationName) : 
                base(endpointConfigurationName)
        {
        }

        
        public CalculatorClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }

        
        public CalculatorClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress)
        {
        }

        
        public CalculatorClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress)
        {
        }

        
        public double AddWithTwoOperands(double x, double y)
        {
            return base.Channel.AddWithTwoOperands(x, y);
        }

        
        public double AddWithThreeOperands(double x, double y, double z)
        {
            return base.Channel.AddWithThreeOperands(x, y, z);
        }

}

实现了我们倒入的Service Contract并提供了相应的Constract,相关的也在前面的Blog提及,这里不用再多说什么了。现在我们毫无疑问,可以直接调用非重载的方法AddWithTwoOperands和AddWithThreeOperands来调用Calculator Service。但是我们需要的不是这样,我们需要的Overloading,在Service 我们实现以Overlaoding的方式提供Service,在Client端我们也希望以相同的方式来调用这个Service。下面我们来看怎么做:

在Client端,重写Service Contract,当然是一Overloading的方式,同时像在Service端一样,通过OperatonContract的Name属性为Operation 制定一个和Service完全匹配的Operation Name。

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace Artech.OverloadableContract.Client
{
    [ServiceContract(Name = "ICalculator")]
   public interface IMyCalculator
    {
        [OperationContract(Name = "AddWithTwoOperands")]
       double Add(double x, double y);

       [OperationContract(Name = "AddWithThreeOperands")]
       double Add(double x, double y, double z);
    }

}

重写Proxy Class

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace Artech.OverloadableContract.Client
{
    class MyCalculatorClient:ClientBase<IMyCalculator>,IMyCalculator
    {
        IMyCalculator Members
    }

}

现在我们有两个Proxy Class,我们同时使用,看看他们会不会返回一样的结果:

using System;
using System.Collections.Generic;
using System.Text;
using Artech.OverloadableContract.Client.CalculatorService;

namespace Artech.OverloadableContract.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin to invocate generated proxy");
            InvocateGeneratedProxy();
            Console.WriteLine("\nBegin to invocate revised proxy");
            InvocateGeneratedProxy();
Console.Read();
        }


        static void InvocateGeneratedProxy()
        {
            using (CalculatorClient calculator = new CalculatorClient())
            
                Console.WriteLine("x + y = {2} where x = {0}and y = {1} ",1,2,calculator.AddWithTwoOperands(1,2));
                Console.WriteLine("x + y + z = {3} where x = {0}and y = {1} and z = {2}", 1, 2, 3,calculator.AddWithThreeOperands(1, 2,3));
            }

        }


        static void InvocateRevisedProxy()
        {
            using (MyCalculatorClient calculator = new MyCalculatorClient())
            {
                Console.WriteLine("x + y = {2} where x = {0}and y = {1} ", 1, 2, calculator.Add(1, 2));
                Console.WriteLine("x + y + z = {3} where x = {0}and y = {1} and z = {2}", 1, 2, 3, calculator.Add(1, 2, 3));
            }

        }

    }

}

同时在加入下面简单的Configuration:

<? xml version="1.0" encoding="utf-8"  ?>
< configuration >
     < system .serviceModel >
         < client >
             < endpoint  address ="http://localhost:1234/calcuator"  binding ="basicHttpBinding"                  contract ="Artech.OverloadableContract.Client.IMyCalculator"   />
                   </ client >
     </ system.serviceModel >
</ configuration >

 

运行Client,下面是Screen Shot,可见两个Proxy是等效的。



WCF相关内容:
[原创]我的WCF之旅(1):创建一个简单的WCF程序
[原创]我的WCF之旅(2):Endpoint Overview
[原创]我的WCF之旅(3):在WCF中实现双向通信(Bi-directional Communication)
[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I
[原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II
[原创]我的WCF之旅(5):Service Contract中的重载(Overloading)
[原创]我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
[原创]我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承
[原创]我的WCF之旅(8):WCF中的Session和Instancing Management
[原创]我的WCF之旅(9):如何在WCF中使用tcpTrace来进行Soap Trace
[原创]我的WCF之旅(10): 如何在WCF进行Exception Handling
[原创]我的WCF之旅(11):再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯

[原创]我的WCF之旅(12):使用MSMQ进行Reliable Messaging
[原创]我的WCF之旅(13):创建基于MSMQ的Responsive Service


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
2月前
|
缓存 监控 数据格式
信息系统架构模型(2) SOA
信息系统架构模型(2) SOA
89 0
|
2月前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
70 0
|
11天前
|
负载均衡 监控 Kubernetes
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
|
1月前
|
边缘计算 Cloud Native
“论SOA在企业集成架构设计中的应用”必过范文,突击2024软考高项论文
SOA架构,即面向服务的架构,它将系统中的所有功能都拆分为一个个独立的服务单元。这些服务通过相互间的沟通与配合,共同完成了整体业务逻辑的运作。在SOA架构中有几个核心概念:服务提供者、服务使用者、服务注册中心、服务规范、服务合同,这些概念清晰地阐述了服务应如何被提
166 6
“论SOA在企业集成架构设计中的应用”必过范文,突击2024软考高项论文
|
18天前
|
消息中间件 安全 NoSQL
「架构」SOA(面向服务的架构)
**SOA**是构建灵活企业IT系统的架构模式,基于服务组件进行设计。它强调服务的自包含、模块化,通过服务识别、抽象、组合和交互实现业务流程。特点包括松耦合、重用性、互操作性和标准化。优点是灵活性、可维护性、可扩展性和成本效益,但也有复杂性、性能和治理问题。设计策略涉及业务能力识别、服务契约定义和服务目录建立。技术栈涵盖Java EE、.NET、SOAP、REST、服务治理工具和各种数据库、消息队列及安全标准。SOA旨在适应变化,但也需妥善管理和规划。
25 0
|
18天前
|
Kubernetes API 微服务
「架构风格」SOA(面向服务)和微服务
**SOA与微服务对比摘要**: - **SOA**:企业级,服务粒度大,重用性强,常通过ESB通信,服务部署集中,技术栈统一。 - **微服务**:服务粒度小,单一职责,轻量级协议如REST,独立部署,技术多样性,去中心化治理。 - **区别**:服务大小、独立性、通信协议、部署方式和技术栈不同,微服务更强调敏捷和独立性。 - **示例**:Python Flask简单示例展示了服务创建,SOA服务间通过HTTP请求通信,微服务每个服务独立运行。 - **权衡**:涉及服务发现、负载均衡、容错和安全,常用技术如Docker、Kubernetes和API网关。
49 0
|
1月前
|
边缘计算 Cloud Native IDE
“论SOA在企业集成架构设计中的应用”写作框架,系统架构设计师
企业应用集成(Enterprise Application Integration, EAI)是每个企业都必须要面对的实际问题。面向服务的企业应用集成是一种基于面向服务体系结构(Service-OrientedArchitecture,SOA)的新型企业应用集成技术,强调将企业和组织内部的资源和业务功能暴露为服务,实现资源共享和系统之间的互操作性,并支持快速地将新的应用以服务的形式加入到已有的集成环境中,增强企业IT环境的灵活性。
|
2月前
|
监控 负载均衡 数据安全/隐私保护
探索微服务架构下的服务网格(Service Mesh)实践
【5月更文挑战第6天】 在现代软件工程的复杂多变的开发环境中,微服务架构已成为构建、部署和扩展应用的一种流行方式。随着微服务架构的普及,服务网格(Service Mesh)作为一种新兴技术范式,旨在提供一种透明且高效的方式来管理微服务间的通讯。本文将深入探讨服务网格的核心概念、它在微服务架构中的作用以及如何在实际项目中落地实施服务网格。通过剖析服务网格的关键组件及其与现有系统的协同工作方式,我们揭示了服务网格提高系统可观察性、安全性和可操作性的内在机制。此外,文章还将分享一些实践中的挑战和应对策略,为开发者和企业决策者提供实用的参考。
|
2月前
|
运维 监控 负载均衡
探索微服务架构下的服务网格(Service Mesh)实践之路
【4月更文挑战第30天】 在现代云计算的大背景下,微服务架构以其灵活性和可扩展性成为众多企业转型的首选。然而,随着服务的激增和网络交互的复杂化,传统的服务通信模式已无法满足需求,服务网格(Service Mesh)应运而生。本文通过分析服务网格的核心组件、运作机制以及在企业中的实际应用案例,探讨了服务网格在微服务架构中的关键作用及其带来的变革,同时提出了实施过程中面临的挑战和解决策略。
|
2月前
|
运维 监控 负载均衡
探索微服务架构下的服务网格(Service Mesh)实践
【4月更文挑战第28天】 在现代云原生应用的后端开发领域,微服务架构已成为一种广泛采用的设计模式。随着分布式系统的复杂性增加,服务之间的通信变得愈加关键。本文将深入探讨服务网格这一创新技术,它旨在提供一种透明且高效的方式来管理、监控和保护微服务间的交互。我们将从服务网格的基本概念出发,分析其在实际应用中的优势与挑战,并通过一个案例研究来展示如何在现有的后端系统中集成服务网格。