當(dāng)今的IT領(lǐng)域,SOA已經(jīng)成為了一個(gè)非常時(shí)髦的詞,對SOA風(fēng)靡的程度已經(jīng)讓很多人對SOA,對面向服務(wù)產(chǎn)生誤解。其中很大一部分人甚至認(rèn)為面向服務(wù)將是面向?qū)ο蟮慕K結(jié),現(xiàn)在的面向?qū)ο髮幻嫦蚍?wù)完全代替。在開始本Blog之前,我先來談?wù)勎覍OA和OO的區(qū)別,首先申明,這只是一家之言,歡迎大家批評指正,并且關(guān)于SO的談?wù)摬皇潜綛log的主題,只是主題的引子,在這里只是簡單討論而已 。OO和SO之間具有共同的部分,在運(yùn)用的領(lǐng)域上存在交集,只有在基于他們交集層面上談?wù)撜l是誰非才有意義,下面是我對SO和OO的區(qū)別。
OO關(guān)注的是如何通過對實(shí)體屬性和行為的封裝來重塑模擬軟件環(huán)境的真實(shí)實(shí)體。對SO關(guān)注的則是對現(xiàn)實(shí)生活的某個(gè)任務(wù)、功能的實(shí)現(xiàn),說得通俗點(diǎn),就是如果做好一件事情。所以對象是對Data和Behavior的封裝,而Service則只是體現(xiàn)了一個(gè)Functionality。Service是粗粒度的,這樣才能導(dǎo)致Contract的穩(wěn)定;Service一般是Stateless的,給定什么樣的輸入,就會有對應(yīng)的確定的輸出;Service是Autonomous,基本上的實(shí)現(xiàn)封裝在Service本身之中,這樣可以使它對其它的Service產(chǎn)生最小的依賴。所以對Service建模是一件不太容易的事情:Service不能太大,否則實(shí)現(xiàn)起來不容易,還會增加對外界的依賴;也不能太小,否則整合這個(gè)Service的成本會令你望而卻步。
Service是可組合的(Composable),通過整合相關(guān)的單獨(dú)的,完成某個(gè)單個(gè)Task或者Activity的小的Service,可以很容易產(chǎn)生一個(gè)大的Service,這個(gè)Service可以完成一個(gè)Functionality的整個(gè)流程。比如我們現(xiàn)在把一個(gè)Task描述成一個(gè)Work flow,如果采用SO的原理來建模,我們可以把組成這個(gè)Workflow的單個(gè)Activity設(shè)計(jì)成一個(gè)service, 然后根據(jù)具體Workflow的特點(diǎn)(比如可能是一個(gè)簡單的Sequential workflow,也可能是一個(gè)基于State machine的workflow)加上相關(guān)的條件很容易的把這些Service整合起來,實(shí)際上通過整合集成,我們生成一個(gè)新的Service。對OO,由于他面對的是一個(gè)的Object,具體在分布式中是一個(gè)個(gè)的Distributed object,要建立一個(gè)Composable object則很難(實(shí)際上這樣也沒有什么意義)。
在OO的概念中,一個(gè)Object的屬性往往就是另一個(gè)Object,一個(gè)Function的實(shí)現(xiàn)往往要調(diào)用另一個(gè)Object的方法,而且這種層次結(jié)構(gòu)可以無限延伸。這樣就會導(dǎo)致真?zhèn)€Object體系變得異常脆弱,經(jīng)常造成牽一發(fā)動全身的狀況。用一個(gè)很時(shí)髦的詞語來表達(dá)的,就是緊耦合(Tightly couple),Object之間的強(qiáng)依賴關(guān)系促成了這種緊耦合的、脆弱的體系結(jié)構(gòu)。而OS則不一樣,由于 構(gòu)成Service體系的單個(gè)Service是自治的,Service之間的調(diào)用(調(diào)用的這個(gè)詞語容易讓人聯(lián)想到RPC,如果找一個(gè)比較貼切的詞語來代替,我覺得consume比較合適)是基于Contract的,Service之間Communication是通過Message的(Message不僅僅是Data的封裝,還是對整個(gè)調(diào)用的描述,同時(shí)基于XML的Message描述和Message的傳遞都是符合一個(gè)開放的標(biāo)準(zhǔn)的),所有這些成就了SO的松耦合(Loosely couple)。
說了這么多,可能大家都覺得我都是在贊揚(yáng)SO,都貶低OO。其實(shí)不然,上面所說的3個(gè)方面都是在講應(yīng)用的構(gòu)建,而不是具體的編程模式。我想表達(dá)的是,曾經(jīng)盛行的基于OO的理論,在企業(yè)應(yīng)用構(gòu)架方面,已經(jīng)不能滿足我們的需要了,我們迫切希望一種全新的理論來指導(dǎo)我們進(jìn)行企業(yè)應(yīng)用的構(gòu)架和集成,而這個(gè)理論非SO不可。
而在編程模型層面,OO仍然是不可替代的編程模式。所以O(shè)O應(yīng)用于Programming,而SO則更多地運(yùn)用在Architecture。既然是這樣,我們必須有一種調(diào)和劑來調(diào)和這兩個(gè)運(yùn)用不同原理的兩個(gè)層面的差異,實(shí)現(xiàn)他們之間的無縫的結(jié)合。比如如何來對繼承,多態(tài),重載等基于OO行為的支持。在這方面,WCF為我們提供了很好的解決方案。所以我說WCF不但是為基于SOA的應(yīng)用架構(gòu)提供了技術(shù)支持,還通過相關(guān)的機(jī)制完成我們提出的這個(gè)“調(diào)和劑”的使命。
在上一篇文章[原創(chuàng)]我的WCF之旅(5):面向服務(wù)架構(gòu)(SOA)對面向?qū)ο缶幊蹋∣OP)的支持——如何實(shí)現(xiàn)Service Contract的重載(Overloading)中,我們談到了WCF如何實(shí)現(xiàn)了對Overloading的支持,在這里我們通過一個(gè)Sample來討論WCF對繼承的支持。這個(gè)Sample中,我們通過一個(gè)WCF Service實(shí)現(xiàn)了提供天氣信息的功能,或者說,我們實(shí)現(xiàn)了一個(gè)用作天氣預(yù)報(bào)的WCF Service。
1. 我們照例來看看真?zhèn)€Solution 的結(jié)構(gòu):
整個(gè)Solution由以下4個(gè)project構(gòu)成:
-
Artech.InheritanceHierarchy.BusinessEntity:這個(gè)Project通過定義的Class封裝了在Client和Service端傳遞的數(shù)據(jù),在本例中,我們定義了兩個(gè)Class:BasicWhetherInfo和WindInfo,他們分別表示Client通過Service獲得的基本天氣情況和刮風(fēng)的情況。
-
Artech.InheritanceHierarchy.Service:這個(gè)Project是我們的Service,包括Service Contract和Service 本身。我們定義兩個(gè)用作天氣預(yù)報(bào)的Service:SimpleWhetherForecast和FullWhetherForecast,前面一個(gè)只用返回簡單的天氣狀況的數(shù)據(jù)(Conditions和Temperature),F(xiàn)ullWhetherForecast在SimpleWhetherForecast基礎(chǔ)上增加了提供風(fēng)向和風(fēng)速的數(shù)據(jù)。
-
-
Artech.InheritanceHierarchy.Client: Client端。
2. 定義Artech.InheritanceHierarchy.BusinessEntity
BasicWhetherInfo.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace Artech.InheritanceHierarchy.BusinessEntity
{
[DataContract]
[KnownType(typeof(WhetherConditions))]
public class BasicWhetherInfo
{
private WhetherConditions _condition;
private double _temperature;
public BasicWhetherInfo(WhetherConditions condition, double temperature)
{
this._condition = condition;
this._temperature = temperature;
}
[DataMember]
public WhetherConditions Condition
{
get { return _condition; }
set { _condition = value; }
}
[DataMember]
public double Temperature
{
get { return _temperature; }
set { _temperature = value; }
}
public override string ToString()
{
return string.Format("Conditions: {0}; Temperature: {1}", this._condition, this._temperature);
}
}
public enum WhetherConditions
{
Clear,
Cloudy,
Overcost,
Rainy
}
}
BasicWhetherInfo包含連個(gè)字段/屬性:Condition和Temperature。屬于Condition不屬于基元(Primitive type)所以我們需要添加 [KnownType(typeof(WhetherConditions))]Attribute(由于跨AppDomain的數(shù)據(jù)傳遞要求傳遞的數(shù)據(jù)先輩Serialization。對于.NET中定義的Primitive type,比如string,int以及其他一些常用的類型,比如datetime,WCF具有一套默認(rèn)的序列化機(jī)制,但是對于另外一些類型,Serializor在執(zhí)行Serialization的時(shí)候 需要獲得相關(guān)類型的Metadata的信息,WCF通過KnownType attribute向Serializor提供Metadata的信息。)。WindInfo中的Direction屬性也是一樣的原理。
WindInfo.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
namespace Artech.InheritanceHierarchy.BusinessEntity
{
[DataContract]
[KnownType(typeof(WindDirection))]
public class WindInfo
{
private WindDirection _direction;
private string _speed;
public WindInfo(WindDirection direction, string speed)
{
this._direction = direction;
this._speed = speed;
}
[DataMember]
public WindDirection Direction
{
get { return _direction; }
set { _direction = value; }
}
[DataMember]
public string Speed
{
get { return _speed; }
set { _speed = value; }
}
public override string ToString()
{
return string.Format("Direction: {0}; Speed: {1}", this._direction, this._speed);
}
}
public enum WindDirection
{
East,
South,
West,
North,
Northeast,
SouthEast,
Northwest,
Southwest
}
}
3. 定義Service:Artech.InheritanceHierarchy.Service
我們首先來定義Service Contract
ISimpleWhetherForecast.cs:
using System;
using System.Collections.Generic;
using System.Text;
using Artech.InheritanceHierarchy.BusinessEntity;
using System.ServiceModel;
namespace Artech.InheritanceHierarchy.Service
{
[ServiceContract]
public interface ISimpleWhetherForecast
{
[OperationContract]
BasicWhetherInfo GetBasicWhetherInfo(string postalcode);
}
}
IFullWhetherForecast.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using Artech.InheritanceHierarchy.BusinessEntity;
namespace Artech.InheritanceHierarchy. Service
{
[ServiceContract]
public interface IFullWhetherForecast:ISimpleWhetherForecast
{
[OperationContract]
WindInfo GetWindInfo(string postalcode);
}
}
我們定義了連個(gè)Interface作為Service Contract。其中IFullWhetherForecast繼承ISimpleWhetherForecast。這里需要注意的是雖然IFullWhetherForecast繼承ISimpleWhetherForecast,但是運(yùn)用在ISimpleWhetherForecast中的ServiceContract Attribute卻不能被IFullWhetherForecast使用,這是因?yàn)樵诙xSystem.ServiceModel. ServiceContractAttribute, 把運(yùn)用在它之上的AttributeUsage的Inherited設(shè)為false, 導(dǎo)致它不能運(yùn)用到派生的Class上面:
using System;
using System.Net.Security;
namespace System.ServiceModel
{
[AttributeUsage(1028, Inherited = false, AllowMultiple = false)]
public sealed class ServiceContractAttribute : Attribute
{
public ServiceContractAttribute();
public Type CallbackContract { get; set; }
public string ConfigurationName { get; set; }
public bool HasProtectionLevel { get; }
public string Name { get; set; }
public string Namespace { get; set; }
public ProtectionLevel ProtectionLevel { get; set; }
public SessionMode SessionMode { get; set; }
}
}
我們接著為這兩個(gè)Service Contract定義對應(yīng)的Service。
SimpleWhetherForecastService:
using System;
using System.Collections.Generic;
using System.Text;
using Artech.InheritanceHierarchy.BusinessEntity;
namespace Artech.InheritanceHierarchy.Service
{
public class SimpleWhetherForecastService:ISimpleWhetherForecast
{
ISimpleWhetherForecast Members#region ISimpleWhetherForecast Members
public BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
{
BasicWhetherInfo info = new BasicWhetherInfo(WhetherConditions.Overcost, 23);
return info;
}
#endregion
}
}
為了代碼的重用,我們讓FullWhetherForecastService繼承自SimpleWhetherForecastService,這樣我們就不必重新定義GetBasicWhetherInfo方法了。
FullWhetherForecastService.cs:
using System;
using System.Collections.Generic;
using System.Text;
using Artech.InheritanceHierarchy.BusinessEntity;
namespace Artech.InheritanceHierarchy.Service
{
public class FullWhetherForecastService:SimpleWhetherForecastService,IFullWhetherForecast
{
IFullWhetherForecast Members#region IFullWhetherForecast Members
public WindInfo GetWindInfo(string postalcode)
{
WindInfo info = new WindInfo(WindDirection.Northwest, "12km/h");
return info;
}
#endregion
}
}
4. Host Service:http://localhost/Artech.InheritanceHierarchy
現(xiàn)在我們完成了Service的定義,現(xiàn)在我們來Host我們定義的Service,這次我們通過IIS的方式來host service。我們首先在該Website中引用Artech.InheritanceHierarchy.Service Project。然后為FullWhetherForecastService定義相應(yīng)的.SVC文件(由于Service Contract的繼承關(guān)系構(gòu)成了一種Service Contract的層次結(jié)構(gòu),從而導(dǎo)致所有定義的Operation都出現(xiàn)在最底層的Contract中,由于SimpleWhetherForecastService的Operation沒有被FullWhetherForecastServiceOverride,所以現(xiàn)在我們只需要Host FullWhetherForecastService就可以了)。
<%@ ServiceHost Service="Artech.InheritanceHierarchy.Service.FullWhetherForecastService,Artech.InheritanceHierarchy.Service" %> 接著我們在Web.config中為Service注冊Endpoint。
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service name="Artech.InheritanceHierarchy.Service.FullWhetherForecastService" behaviorConfiguration="returnFaults">
<endpoint contract="Artech.InheritanceHierarchy.Service.IFullWhetherForecast" binding="wsHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true">
<assemblies>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="Microsoft.Transactions.Bridge, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="SMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.IdentityModel.Selectors, Version=3.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Web.RegularExpressions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Messaging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/></assemblies></compilation>
</system.web>
</configuration>
5. 定義Client:Artech.InheritanceHierarchy.Client
到現(xiàn)在為止,我們完成了Service的定義和Host的工作,換句話說現(xiàn)在我們定義的Whether
Forecast service已經(jīng)可以訪問,并暴露在這樣的一個(gè)Address上:http://localhost/Artech.InheritanceHierarchy/FullWhetherForecastService.svc?,F(xiàn)在我們來編寫我們Client來訪問這個(gè)Service。值得一說的是,現(xiàn)在這個(gè)Sample中,Client是一個(gè)獨(dú)立的Application,我們既沒有讓他引用我們定義的Artech.InheritanceHierarchy.BusinessEntity(在WCF中,這個(gè)相當(dāng)于Data Contract),也沒有讓它和Service共享同一個(gè)Service Contract。這很類似于在純Web環(huán)境下調(diào)用Service。
我們通過添加Service reference的方式生成我們Client端的code, WCF中的添加Service reference同Web Service中的添加Web reference相識。通過添加Service reference,WCF會為我們生成基于Client的service contract,data contract,proxy,configuraiton,甚至為我們添加System.ServiceNModel dll的引用。下面就是我們生成的Code:


//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.312
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Artech.InheritanceHierarchy.Client.WhetherForecastService
{
using System.Runtime.Serialization;
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
"y")]
[System.SerializableAttribute()]
public partial class BasicWhetherInfo : object, System.Runtime.Serialization.IExtensibleDataObject
{
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions ConditionField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private double TemperatureField;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
{
get
{
return this.extensionDataField;
}
set
{
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions Condition
{
get
{
return this.ConditionField;
}
set
{
this.ConditionField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public double Temperature
{
get
{
return this.TemperatureField;
}
set
{
this.TemperatureField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
"y")]
public enum WhetherConditions : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
Clear = 0,
[System.Runtime.Serialization.EnumMemberAttribute()]
Cloudy = 1,
[System.Runtime.Serialization.EnumMemberAttribute()]
Overcost = 2,
[System.Runtime.Serialization.EnumMemberAttribute()]
Rainy = 3,
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
"y")]
[System.SerializableAttribute()]
public partial class WindInfo : object, System.Runtime.Serialization.IExtensibleDataObject
{
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection DirectionField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string SpeedField;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
{
get
{
return this.extensionDataField;
}
set
{
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection Direction
{
get
{
return this.DirectionField;
}
set
{
this.DirectionField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Speed
{
get
{
return this.SpeedField;
}
set
{
this.SpeedField = value;
360docimg_501_ }
360docimg_502_ }
360docimg_503_ }
360docimg_504_
360docimg_505_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
360docimg_506_ [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
360docimg_507_ "y")]
360docimg_508_ public enum WindDirection : int
360docimg_509_360docimg_510_ 360docimg_511_{
360docimg_512_
360docimg_513_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_514_ East = 0,
360docimg_515_
360docimg_516_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_517_ South = 1,
360docimg_518_
360docimg_519_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_520_ West = 2,
360docimg_521_
360docimg_522_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_523_ North = 3,
360docimg_524_
360docimg_525_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_526_ Northeast = 4,
360docimg_527_
360docimg_528_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_529_ SouthEast = 5,
360docimg_530_
360docimg_531_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_532_ Northwest = 6,
360docimg_533_
360docimg_534_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_535_ Southwest = 7,
360docimg_536_ }
360docimg_537_
360docimg_538_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
360docimg_539_ [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast")]
360docimg_540_ public interface IFullWhetherForecast
360docimg_541_360docimg_542_ 360docimg_543_{
360docimg_544_
360docimg_545_ [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfo", ReplyAction="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfoResponse")]
360docimg_546_ Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode);
360docimg_547_
360docimg_548_ [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFullWhetherForecast/GetWindInfo", ReplyAction="http://tempuri.org/IFullWhetherForecast/GetWindInfoResponse")]
360docimg_549_ Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode);
360docimg_550_ }
360docimg_551_
360docimg_552_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
360docimg_553_ public interface IFullWhetherForecastChannel : Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast, System.ServiceModel.IClientChannel
360docimg_554_360docimg_555_ 360docimg_556_{
360docimg_557_ }
360docimg_558_
360docimg_559_ [System.Diagnostics.DebuggerStepThroughAttribute()]
360docimg_560_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
360docimg_561_ public partial class FullWhetherForecastClient : System.ServiceModel.ClientBase<Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast>, Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast
360docimg_562_360docimg_563_ 360docimg_564_{
360docimg_565_
360docimg_566_ public FullWhetherForecastClient()
360docimg_567_360docimg_568_ 360docimg_569_{
360docimg_570_ }
360docimg_571_
360docimg_572_ public FullWhetherForecastClient(string endpointConfigurationName) :
360docimg_573_ base(endpointConfigurationName)
360docimg_574_360docimg_575_ 360docimg_576_{
360docimg_577_ }
360docimg_578_
360docimg_579_ public FullWhetherForecastClient(string endpointConfigurationName, string remoteAddress) :
360docimg_580_ base(endpointConfigurationName, remoteAddress)
360docimg_581_360docimg_582_ 360docimg_583_{
360docimg_584_ }
360docimg_585_
360docimg_586_ public FullWhetherForecastClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
360docimg_587_ base(endpointConfigurationName, remoteAddress)
360docimg_588_360docimg_589_ 360docimg_590_{
360docimg_591_ }
360docimg_592_
360docimg_593_ public FullWhetherForecastClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
360docimg_594_ base(binding, remoteAddress)
360docimg_595_360docimg_596_ 360docimg_597_{
360docimg_598_ }
360docimg_599_
360docimg_600_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
360docimg_601_360docimg_602_ 360docimg_603_{
360docimg_604_ return base.Channel.GetBasicWhetherInfo(postalcode);
360docimg_605_ }
360docimg_606_
360docimg_607_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode)
360docimg_608_360docimg_609_ 360docimg_610_{
360docimg_611_ return base.Channel.GetWindInfo(postalcode);
360docimg_612_ }
360docimg_613_ }
360docimg_614_}
360docimg_615_Code比較長,我們現(xiàn)在一部分一部分地來分析。
Part I:Data Contract
360docimg_616_360docimg_617_
360docimg_618_[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")] [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
360docimg_619_ "y")]
360docimg_620_ [System.SerializableAttribute()]
360docimg_621_ public partial class BasicWhetherInfo : object, System.Runtime.Serialization.IExtensibleDataObject
360docimg_622_360docimg_623_ 360docimg_624_{
360docimg_625_
360docimg_626_ [System.NonSerializedAttribute()]
360docimg_627_ private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
360docimg_628_
360docimg_629_ [System.Runtime.Serialization.OptionalFieldAttribute()]
360docimg_630_ private Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions ConditionField;
360docimg_631_
360docimg_632_ [System.Runtime.Serialization.OptionalFieldAttribute()]
360docimg_633_ private double TemperatureField;
360docimg_634_
360docimg_635_ public System.Runtime.Serialization.ExtensionDataObject ExtensionData
360docimg_636_360docimg_637_ 360docimg_638_{
360docimg_639_ get
360docimg_640_360docimg_641_ 360docimg_642_{
360docimg_643_ return this.extensionDataField;
360docimg_644_ }
360docimg_645_ set
360docimg_646_360docimg_647_ 360docimg_648_{
360docimg_649_ this.extensionDataField = value;
360docimg_650_ }
360docimg_651_ }
360docimg_652_
360docimg_653_ [System.Runtime.Serialization.DataMemberAttribute()]
360docimg_654_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.WhetherConditions Condition
360docimg_655_360docimg_656_ 360docimg_657_{
360docimg_658_ get
360docimg_659_360docimg_660_ 360docimg_661_{
360docimg_662_ return this.ConditionField;
360docimg_663_ }
360docimg_664_ set
360docimg_665_360docimg_666_ 360docimg_667_{
360docimg_668_ this.ConditionField = value;
360docimg_669_ }
360docimg_670_ }
360docimg_671_
360docimg_672_ [System.Runtime.Serialization.DataMemberAttribute()]
360docimg_673_ public double Temperature
360docimg_674_360docimg_675_ 360docimg_676_{
360docimg_677_ get
360docimg_678_360docimg_679_ 360docimg_680_{
360docimg_681_ return this.TemperatureField;
360docimg_682_ }
360docimg_683_ set
360docimg_684_360docimg_685_ 360docimg_686_{
360docimg_687_ this.TemperatureField = value;
360docimg_688_ }
360docimg_689_ }
360docimg_690_ }
360docimg_691_
360docimg_692_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
360docimg_693_ [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
360docimg_694_ "y")]
360docimg_695_ public enum WhetherConditions : int
360docimg_696_360docimg_697_ 360docimg_698_{
360docimg_699_
360docimg_700_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_701_ Clear = 0,
360docimg_702_
360docimg_703_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_704_ Cloudy = 1,
360docimg_705_
360docimg_706_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_707_ Overcost = 2,
360docimg_708_
360docimg_709_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_710_ Rainy = 3,
360docimg_711_ }
360docimg_712_
360docimg_713_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
360docimg_714_ [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
360docimg_715_ "y")]
360docimg_716_ [System.SerializableAttribute()]
360docimg_717_ public partial class WindInfo : object, System.Runtime.Serialization.IExtensibleDataObject
360docimg_718_360docimg_719_ 360docimg_720_{
360docimg_721_
360docimg_722_ [System.NonSerializedAttribute()]
360docimg_723_ private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
360docimg_724_
360docimg_725_ [System.Runtime.Serialization.OptionalFieldAttribute()]
360docimg_726_ private Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection DirectionField;
360docimg_727_
360docimg_728_ [System.Runtime.Serialization.OptionalFieldAttribute()]
360docimg_729_ private string SpeedField;
360docimg_730_
360docimg_731_ public System.Runtime.Serialization.ExtensionDataObject ExtensionData
360docimg_732_360docimg_733_ 360docimg_734_{
360docimg_735_ get
360docimg_736_360docimg_737_ 360docimg_738_{
360docimg_739_ return this.extensionDataField;
360docimg_740_ }
360docimg_741_ set
360docimg_742_360docimg_743_ 360docimg_744_{
360docimg_745_ this.extensionDataField = value;
360docimg_746_ }
360docimg_747_ }
360docimg_748_
360docimg_749_ [System.Runtime.Serialization.DataMemberAttribute()]
360docimg_750_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindDirection Direction
360docimg_751_360docimg_752_ 360docimg_753_{
360docimg_754_ get
360docimg_755_360docimg_756_ 360docimg_757_{
360docimg_758_ return this.DirectionField;
360docimg_759_ }
360docimg_760_ set
360docimg_761_360docimg_762_ 360docimg_763_{
360docimg_764_ this.DirectionField = value;
360docimg_765_ }
360docimg_766_ }
360docimg_767_
360docimg_768_ [System.Runtime.Serialization.DataMemberAttribute()]
360docimg_769_ public string Speed
360docimg_770_360docimg_771_ 360docimg_772_{
360docimg_773_ get
360docimg_774_360docimg_775_ 360docimg_776_{
360docimg_777_ return this.SpeedField;
360docimg_778_ }
360docimg_779_ set
360docimg_780_360docimg_781_ 360docimg_782_{
360docimg_783_ this.SpeedField = value;
360docimg_784_ }
360docimg_785_ }
360docimg_786_ }
360docimg_787_
360docimg_788_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
360docimg_789_ [System.Runtime.Serialization.DataContractAttribute(Namespace="http://schemas.datacontract.org/2004/07/Artech.InheritanceHierarchy.BusinessEntit" +
360docimg_790_ "y")]
360docimg_791_ public enum WindDirection : int
360docimg_792_360docimg_793_ 360docimg_794_{
360docimg_795_
360docimg_796_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_797_ East = 0,
360docimg_798_
360docimg_799_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_800_ South = 1,
360docimg_801_
360docimg_802_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_803_ West = 2,
360docimg_804_
360docimg_805_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_806_ North = 3,
360docimg_807_
360docimg_808_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_809_ Northeast = 4,
360docimg_810_
360docimg_811_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_812_ SouthEast = 5,
360docimg_813_
360docimg_814_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_815_ Northwest = 6,
360docimg_816_
360docimg_817_ [System.Runtime.Serialization.EnumMemberAttribute()]
360docimg_818_ Southwest = 7,
360docimg_819_}
360docimg_820_
把這段代碼基本上對應(yīng)的我們在Artech.InheritanceHierarchy.BusinessEntity定義的Data Contract:兩個(gè)Class:BasicWhetherInfo& WindInfo和連個(gè)Enum:WindDirection& WhetherConditions。不過有一點(diǎn)我覺得奇怪的是我們原來的BasicWhetherInfo& WindInfo的定義中,我Override了ToString方法,但是在生成的Class中,卻沒有相應(yīng)的Code。我不清楚Microsoft對此事作怎么樣的考慮,還是忽略了這一點(diǎn)。
Part II Service Contract
360docimg_821_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] [System.ServiceModel.ServiceContractAttribute(ConfigurationName="Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast")]
360docimg_822_ public interface IFullWhetherForecast
360docimg_823_360docimg_824_ 360docimg_825_{
360docimg_826_ [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfo", ReplyAction="http://tempuri.org/ISimpleWhetherForecast/GetBasicWhetherInfoResponse")]
360docimg_827_ Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode);
360docimg_828_
360docimg_829_ [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IFullWhetherForecast/GetWindInfo", ReplyAction="http://tempuri.org/IFullWhetherForecast/GetWindInfoResponse")]
360docimg_830_ Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode);
360docimg_831_ }
360docimg_832_
在Service端,我們通過運(yùn)用繼承定義了一套Service contract的層次結(jié)構(gòu),并為處于最底層的Contract公開了一個(gè)Endpoint。在Client端,我們通過添加Service reference的方式生成了Client的Service contract的結(jié)構(gòu)。不過Client的Service contract的結(jié)構(gòu)是一種扁平的結(jié)構(gòu):通過一個(gè)Contract定義所有的Operation。
Part III Proxy
360docimg_833_[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
360docimg_834_ public interface IFullWhetherForecastChannel : Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast, System.ServiceModel.IClientChannel
360docimg_835_360docimg_836_ 360docimg_837_{
360docimg_838_ }
360docimg_839_
360docimg_840_ [System.Diagnostics.DebuggerStepThroughAttribute()]
360docimg_841_ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
360docimg_842_ public partial class FullWhetherForecastClient : System.ServiceModel.ClientBase<Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast>, Artech.InheritanceHierarchy.Client.WhetherForecastService.IFullWhetherForecast
360docimg_843_360docimg_844_ 360docimg_845_{
360docimg_846_
360docimg_847_ public FullWhetherForecastClient()
360docimg_848_360docimg_849_ 360docimg_850_{
360docimg_851_ }
360docimg_852_
360docimg_853_ public FullWhetherForecastClient(string endpointConfigurationName) :
360docimg_854_ base(endpointConfigurationName)
360docimg_855_360docimg_856_ 360docimg_857_{
360docimg_858_ }
360docimg_859_
360docimg_860_ public FullWhetherForecastClient(string endpointConfigurationName, string remoteAddress) :
360docimg_861_ base(endpointConfigurationName, remoteAddress)
360docimg_862_360docimg_863_ 360docimg_864_{
360docimg_865_ }
360docimg_866_
360docimg_867_ public FullWhetherForecastClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
360docimg_868_ base(endpointConfigurationName, remoteAddress)
360docimg_869_360docimg_870_ 360docimg_871_{
360docimg_872_ }
360docimg_873_
360docimg_874_ public FullWhetherForecastClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
360docimg_875_ base(binding, remoteAddress)
360docimg_876_360docimg_877_ 360docimg_878_{
360docimg_879_ }
360docimg_880_
360docimg_881_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
360docimg_882_360docimg_883_ 360docimg_884_{
360docimg_885_ return base.Channel.GetBasicWhetherInfo(postalcode);
360docimg_886_ }
360docimg_887_
360docimg_888_ public Artech.InheritanceHierarchy.Client.WhetherForecastService.WindInfo GetWindInfo(string postalcode)
360docimg_889_360docimg_890_ 360docimg_891_{
360docimg_892_ return base.Channel.GetWindInfo(postalcode);
360docimg_893_ }
360docimg_894_}
360docimg_895_
現(xiàn)在我們可以通過FullWhetherForecastClient這個(gè)Proxy Class來訪問Service了。雖然能完成我們的所有操作,但是這樣的代碼總覺得很別扭。我們希望的是以Service端定義結(jié)構(gòu)進(jìn)行Service的調(diào)用:Client具有兩個(gè)Proxy:SimpleWhetherForecastClient和FullWhetherForecastClient。FullWhetherForecastClient繼承自SimpleWhetherForecastClient。我們先刪除我們生成的Code,按照以下的步驟來實(shí)現(xiàn)這樣功能。
Step 1:定義Client端的Service Contract
ISimpleWhetherForecast
360docimg_896_using System;
360docimg_897_using System.Collections.Generic;
360docimg_898_using System.Text;
360docimg_899_
360docimg_900_using Artech.InheritanceHierarchy.BusinessEntity;
360docimg_901_using System.ServiceModel;
360docimg_902_
360docimg_903_namespace Artech.InheritanceHierarchy.Client
360docimg_904_360docimg_905_360docimg_906_{
360docimg_907_ [ServiceContract]
360docimg_908_ public interface ISimpleWhetherForecast
360docimg_909_360docimg_910_ 360docimg_911_{
360docimg_912_ [OperationContract]
360docimg_913_ BasicWhetherInfo GetBasicWhetherInfo(string postalcode);
360docimg_914_ }
360docimg_915_}
360docimg_916_
IFullWhetherForecast.cs
360docimg_917_using System;
360docimg_918_using System.Collections.Generic;
360docimg_919_using System.Text;
360docimg_920_using System.ServiceModel;
360docimg_921_using Artech.InheritanceHierarchy.BusinessEntity;
360docimg_922_
360docimg_923_namespace Artech.InheritanceHierarchy. Client
360docimg_924_360docimg_925_360docimg_926_{
360docimg_927_ [ServiceContract]
360docimg_928_ public interface IFullWhetherForecast:ISimpleWhetherForecast
360docimg_929_360docimg_930_ 360docimg_931_{
360docimg_932_ [OperationContract]
360docimg_933_ WindInfo GetWindInfo(string postalcode);
360docimg_934_ }
360docimg_935_}
360docimg_936_
除了namespace,和Service端的contract沒有什么區(qū)別。
Step2:引用Artech.InheritanceHierarchy.BusinessEntity
Step3: 配置Endpoint
360docimg_937_<?xml version="1.0" encoding="utf-8" ?>
360docimg_938_<configuration>
360docimg_939_ <system.serviceModel>
360docimg_940_ <client>
360docimg_941_ <endpoint address="http://localhost/Artech.InheritanceHierarchy/FullWhetherForecastService.svc"
360docimg_942_ binding="wsHttpBinding" bindingConfiguration="" contract="Artech.InheritanceHierarchy.Client.IFullWhetherForecast"/>
360docimg_943_ </client>
360docimg_944_ </system.serviceModel>
360docimg_945_</configuration>
360docimg_946_
因?yàn)镾ervice端的Endpoint對應(yīng)的Contract是Artech.InheritanceHierarchy.Service IFullWhetherForecast,所以我們適應(yīng)對應(yīng)的Client端的Contract:Artech.InheritanceHierarchy.Client.IFullWhetherForecast
Step 4:建立Proxy
SimpleWhetherForecastClient.cs
360docimg_947_using System;
360docimg_948_using System.Collections.Generic;
360docimg_949_using System.Text;
360docimg_950_using System.ServiceModel;
360docimg_951_using Artech.InheritanceHierarchy.BusinessEntity;
360docimg_952_
360docimg_953_namespace Artech.InheritanceHierarchy.Client
360docimg_954_360docimg_955_360docimg_956_{
360docimg_957_ public class SimpleWhetherForecastClient:ClientBase<IFullWhetherForecast>,ISimpleWhetherForecast
360docimg_958_360docimg_959_ 360docimg_960_{
360docimg_961_360docimg_962_ ISimpleWhetherForecast Members#region ISimpleWhetherForecast Members
360docimg_963_
360docimg_964_ public BasicWhetherInfo GetBasicWhetherInfo(string postalcode)
360docimg_965_360docimg_966_ 360docimg_967_{
360docimg_968_ return this.Channel.GetBasicWhetherInfo(postalcode);
360docimg_969_ }
360docimg_970_
360docimg_971_ #endregion
360docimg_972_ }
360docimg_973_}
360docimg_974_
FullWhetherForecastClient.cs
360docimg_975_using System;
360docimg_976_using System.Collections.Generic;
360docimg_977_using System.Text;
360docimg_978_
360docimg_979_namespace Artech.InheritanceHierarchy.Client
360docimg_980_360docimg_981_360docimg_982_{
360docimg_983_ public class FullWhetherForecastClient:SimpleWhetherForecastClient,IFullWhetherForecast
360docimg_984_360docimg_985_ 360docimg_986_{
360docimg_987_
360docimg_988_360docimg_989_ IFullWhetherForecast Members#region IFullWhetherForecast Members
360docimg_990_
360docimg_991_ public Artech.InheritanceHierarchy.BusinessEntity.WindInfo GetWindInfo(string postalcode)
360docimg_992_360docimg_993_ 360docimg_994_{
360docimg_995_ return this.Channel.GetWindInfo(postalcode);
360docimg_996_ }
360docimg_997_
360docimg_998_ #endregion
360docimg_999_ }
360docimg_1000_}
360docimg_1001_
現(xiàn)在通過SimpleWhetherForecastClient和FullWhetherForecastClient完全以O(shè)O的方式優(yōu)雅地調(diào)用Whether forecast service。