程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 使用Microsoft Robotics Studio實現和擴展一個Service Contract

使用Microsoft Robotics Studio實現和擴展一個Service Contract

編輯:關於.NET

這篇文章描述了使用三種方法來實現或擴展一個通用服務協議(generic service contract),其中 包括實現一個通用服務協議、擴展一個服務協議以及多頭服務(Multi-Headed Service),這個實例中使 用的通用的服務協議是在Service Tutorial 8 (C#) - Generic Service Declaration.所創建的。

這個實例由C#實現,可以在下面的目錄中找到這個項目:

Samples"ServiceTutorials"Tutorial9"CSharp

第一步:創建項目

由於項目需要擴展一個通用服務協議(generic service contract),所以項目中需要引用Service Tutorial 8項目生成的dll文件,在Service Tutorial 9項目你會看到它實現了三個個服務,在一個項目 中實現多個服務的話,要確保這些服務的命名空間是不同的哦。

第二步:實現一個通用服務協議

第一個服務實例是GenericServiceImplementation,實現這個服務的文件是 GenericServiceImplementation.cs 和 GenericServiceImplementationTypes.cs,這個服務僅僅是實現 了一個通用服務協議。

服務類型聲明(Service Type Declarations):

因為在這個服務中使用了通用服務協議,因此它不需要我們去定義他的狀態和操作,這些在通用服務 協議已經定義好了,看看ServiceTutorial8就知道了,但是它還是需要一個協議標識(Contract identifier),因為需要用這個標識來找到這個服務,服務標識定義如下:

 1 /// <summary>

 2 /// Generic Service Implementation Contract Identifier

 3 /// </summary>

 4 public sealed class Contract

 5 

 6 {

 7     /// The Unique Contract Identifier for this service

 8 

 9     [DataMember()]

10     public const String Identifier = "http://schemas.tempuri.org/2007/08/servicetutorial9/genericservice/implementation.html";

11 }

12

引用通用協議(Referencing the Generic Contract)

在項目中引用通用服務協議代理程序集(generic contract's proxy assembly),一定要引用代理程 序集,即*Proxy.dll,這個文件可以在msrs安裝根目錄下的bin文件夾中找到,為這個通用服務協議的命 名空間定義一個別名,如下:

using generic = ServiceTutorial8.Proxy;

服務實現

這個服務的實現和其他的服務基本沒有什麼區別,有兩點如下:

1、 服務實現類需要用AlternateContract屬性標記,用來指示在這個服務中使用的是通用服務協議 。

 1 /// <summary>

 2 /// This service provides an implementation of the generic service

 3 /// </summary>

 4 [Contract(Contract.Identifier)]

 5 [AlternateContract(generic.Contract.Identifier)]

 6 [DisplayName("Service Tutorial 9: Generic Service Implementation")]

 7 [Description("This service implements the generic service provided in Service 

Tutorial 8.")]

 8 [DssServiceDescription("http://msdn.microsoft.com/library/bb727257.aspx")]

 9 public class ImplementationService : DsspServiceBase

10

2、因為這個服務自己沒有定義狀態和操作,狀態和操作都在通用服務協議有所定義了,只需在服務中 使用罷了。如下:

 1 // The state of this service is exactly that of the generic service

 2 [ServiceState]

 3 private generic.GenericState _state = new generic.GenericState();

 4 

 5 // The operations port is exactly that of the generic service

 6 [ServicePort("/GenericServiceImplementation", AllowMultipleInstances = false)]

 7 private generic.GenericServiceOperations _mainPort = new generic.GenericServiceOperations();

 8 

 9 /// <summary>

10 /// Default Service Constructor

11 /// </summary>

12 public ImplementationService(DsspServiceCreationPort creationPort)

13     :

14         base(creationPort)

15 {

16 }

17

剩下的工作是為通用協議中的定義的消息操作(message operations)添加處理方法(handler),如 下代碼定義了Get操作的處理方法:

 1         /// Get Handler

 2         /// </summary>

 3         /// <param name="get"></param>

 4         /// <returns></returns>

 5         // Note that this service does not need to implement Get unless there are

 6         // some specific functions that it must perform

 7         [ServiceHandler(ServiceHandlerBehavior.Concurrent)]

 8 

 9         public virtual IEnumerator<ITask> GetHandler(generic.Get get)

10         {

11             get.ResponsePort.Post(_state);

12             yield break;

13         }

14

運行服務

運行服務後,在浏覽器中Service Directory可以查看到兩個服務genericserviceimplementation 和 genericserviceimplementation/servicetutorial8.因為服務沒有擴展通用服務協議,所以這兩個服務的 狀態和操作是一樣的。

圖1,運行服務,如圖紅框標出DSS節點中運行了兩個服務(genericserviceimplementation and genericserviceimplementation/servicetutorial8),兩個服務有相同的狀態和操作類型。

第三步:擴展一個通用服務協議

第二個服務提供了對通用服務協議的實現,同時又添加了一個自己的狀態和消息操作,這樣做的目的 是:如果服務使用者只知道通用服務協議所定義狀態和操作的話,他可以很容易使用這個服務,並且,這 個服務還允許使用者使用擴展的狀態和操作。

服務類型聲明

和前面實現的服務不同,前面的服務沒有自己的服務類型聲明,而這個服務有自己服務類型聲明,包 括協議標識,服務狀態以及服務操作,其中服務狀態繼承自通用服務中的狀態。

協議標識聲明如下:

1 /// <summary>

2 /// Generic Service Extension Contract Identifier

3 /// /// </summary>

4 public static class Contract

5 {

6     public const string Identifier =

 "http://schemas.tempuri.org/2007/08/servicetutorial9/genericservice/extension.html";

7 }

8 
其中的服務狀態繼承自通用服務協議中的狀態,同時有所擴展,添加了Age屬性,繼承實現如下:

 1 [DataContract]

 2 [DisplayName("Service Tutorial 9: Extension Service State")]

 3 [Description("This service state extends the generic service state provided in

 Service Tutorial 8.")]

 4 public class ExtensionState : generic.GenericState

 5 {

 6     int _age; 

 7     [DataMember]

 8     [DisplayName("Age")]

 9     [Description("Specifies the age of a person.")]

10     public int Age

11     {

12         get { return _age; }

13         set { _age = value; }

14     }

15  

16

除了添加了新的屬性,又添加了構造函數,這個構造函數通過一個基類的實例來初始化子類對象,更 有意思的是,又添加了個類型轉換方法,這個方法將子類轉換為父類,這樣做的原因是,有時候我們想獲 得一個通用服務協議中定義的狀態對象的序列化對象,而不包括子類所擴展的其他信息,假如僅僅使用 CLR所默認的隱式類型轉換,我們得到的對象仍舊是子類對象,因此,要獲得一個基類型的序列化對象, 只能顯示的實現一個基類對象,而不是隱式轉換。

 1 internal ExtensionState(generic.GenericState state)

 2 {

 3     this.FirstName = state.FirstName;

 4     this.LastName = state.LastName;

 5     this.Age = -1;

 6 }

 7 internal generic.GenericState ToGenericState()

 8 {

 9 

10     generic.GenericState gen = new generic.GenericState();

11     gen.FirstName = this.FirstName;

12     gen.LastName = this.LastName;

13     return gen;

14 }

15 

16

這個實例中我們又添加了一個消息操作類型,即UpdateAge操作,假如我們沒有擴展服務狀態而只是添 加一個操作,我們可以重用通用服務協議定義的消息操作類,但是這裡我們只能重新定義一個服務操作。

 1 /// <summary>

 2 /// Generic Service Extension Main Operations Port

 3 /// </summary>

 4 [ServicePort]

 5 public class GenericServiceExtensionOperations :

 6 

 7     PortSet<DsspDefaultLookup, DsspDefaultDrop, Get, Replace, UpdateAge>

 8 {

 9 

10 }

11

服務實現

和前面的服務的實現方式不一樣,前面服務完全使用通用服務的協議中定義的狀態和操作,而這個服 務的狀態和主端口都使用的擴展的狀態和操作,因為主端口使用的是擴展的操作類型,所以它並不能處理 從備用端口傳來的消息,因此,和前面服務不同的是,我們還需要聲明另一個端口用來處理通用服務協議 中定義的操作,這個端口即備用端口(AlternateServicePort),在對端口的聲明上和前面的服務有所不 同,前面的服務在類(ExtensionService)層次上使用AlternateContract屬性,這裡我們用 AlternateServicePort屬性來標記備用端口,代碼如下:

 1 // The state of this service is an extension of the generic service

 2 private ExtensionState _state = new ExtensionState();

 3  

 4 // The operations port is an extension of the generic service in that it supports UPDATE 

as well

 5 [ServicePort("/GenericServiceExtension", AllowMultipleInstances = false)]

 6 private GenericServiceExtensionOperations _mainPort = new 

GenericServiceExtensionOperations();

 7  

 8 // The alternate port where we only have the generic service operations (without UPDATE)

 9 [AlternateServicePort(AlternateContract = generic.Contract.Identifier)]

10 private generic.GenericServiceOperations _altPort = new generic.GenericServiceOperations

();

11

注意:

AlternateContract和AlternateServicePort是不能同時使用的哦,當你將通用服務協議所定義的操作 類用作主端口時,那麼使用AlternateContract屬性來標記這個服務,而如果你沒有將通用服務協議定義 的操作類作為主端口,而是將它作為備用端口,那就要在端口聲明時為其標記AlternateServicePort屬性 。

剩下的事就是為消息定義處理方法,因為這個服務中有兩個端口,每個端口都有自己的消息類型,即 主端口和備用端口各自接收自己所定義的消息,代碼如下:

這段是處理主端口傳來的消息:

 1 /// <summary>

 2 /// Get Handler

 3 /// </summary>

 4 /// <param name="get"></param>

 5 /// <returns></returns>

 6 [ServiceHandler(ServiceHandlerBehavior.Concurrent)]

 7 

 8 public virtual IEnumerator<ITask> GetHandler(Get get)

 9 

10 {

11     get.ResponsePort.Post(_state);

12     yield break;

13 

14 }

15 

16  

17 

18 /// <summary>

19 /// Replace Handler

20 /// </summary>

21 /// <param name="replace"></param>

22 /// <returns></returns>

23 [ServiceHandler(ServiceHandlerBehavior.Exclusive)]

24 public virtual IEnumerator<ITask> ReplaceHandler(Replace replace)

25 

26 {

27 

28     _state = replace.Body;

29     replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);

30     yield break;

31 

32 }

33 

34  

35 

36 /// <summary>

37 /// Update Handler

38 /// </summary>

39 /// <param name="update"></param>

40 /// <returns></returns>

41 [ServiceHandler(ServiceHandlerBehavior.Exclusive)]

42 

43 public virtual IEnumerator<ITask> UpdateAgeHandler(UpdateAge update)

44 

45 {

46 

47     _state.Age = update.Body.Age;

48     update.ResponsePort.Post(DefaultUpdateResponseType.Instance);

49     yield break;

50 

51 }

52 

53  

54 

55

這段是處理從備用端口傳來的消息的代碼,這裡使用了服務狀態中所定義的類型轉換方法 ToGenericState,從子類對象中抽離出了父類對象,這樣的好處是,提高了這個服務的通用性,因為父類 對象是在通用服務協議中定義的,是大家所共知的,是規范,和其他服務交互的時候通常是傳遞的這個通 用的狀態對象的哦,彼此之間耦合就降了下來,這和面向對象中的多態類似哦。

同時要注意這些處理方法的屬性中多了一個參數PortFieldName,這個參數用來告訴DSS運行時環境將 這個處理方法附加到名字為_altPort的備用端口(Alternate Port)上。

沒有使用這個參數的處理方法會被DSS環境會附加到主端口(Service Port)。

/// <summary>
/// Get Handler
/// </summary>
/// <param name="get"></param>
/// <returns></returns>
[ServiceHandler(ServiceHandlerBehavior.Concurrent, PortFieldName = "_altPort")]
public virtual IEnumerator<ITask> GenericGetHandler(generic.Get get)
{
get.ResponsePort.Post(_state.ToGenericState());
yield break;
}
/// <summary>
/// Replace Handler
/// </summary>
/// <param name="replace"></param>
/// <returns></returns>
[ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_altPort")]
public virtual IEnumerator<ITask> GenericReplaceHandler(generic.Replace replace)
{
_state = new ExtensionState(replace.Body);
replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
yield break;
}

運行服務

運行服務後,從服務目錄同樣可以看到兩個服務(genericserviceextension and genericserviceextension/servicetutorial8),但是和前面實現通用協議的服務不同,這兩個服務有不 同的狀態。

圖2-運行服務後在目錄中出現兩個服務(genericserviceextension and genericserviceextension/servicetutorial8)這兩個服有不同的狀態和操作,包括相同的狀態實例。

第一個服務(genericserviceextension)包含了擴展的狀態和操作,第二個服務 (genericserviceextension/servicetutorial8)包含通用的狀態和操作。

圖3-第二個服務(genericserviceextension/servicetutorial8)包含通用的狀態和操作,這樣其他 的服務可以把這個服務視為通用服務而與之通信了。

第四步:實現一個多例服務(multi-headed service)

最後一個服務實例在(MultiFunctionService.cs and MultiFunctionServiceTypes.cs)定義,MSDN 中稱它為(multi-headed service),我們稱他為多例服務,即在一個服務中實現多個狀態和端口,端口 之間是相互獨立並行執行,就好像一個服務中包含了多個獨立的服務實例,從外部看來,這些服務都是相 互獨立的,他們可能共享了一個資源或者相互之間有比較高的耦合度,當開發多例服務時,還是需要考慮 下把這些服務分開來實現是不是更好呢?因為分開實現會有更大的靈活性。

多例服務的實現和前面所說的服務實現方法是一樣的,他可能會有多個操作端口,一個主端口(main port),其他的是備用端口(alternate port),並且還要為這些端口分別實現消息處理方法。

和前面服務不同的是,多例服務包括多個狀態對象實例,這些狀態實例看起來並不相關。

1 // The first state of this multi headed service
2 private AddressState _address = new AddressState();
3
4 // The operations port used for the first service
5 [ServicePort("/AddressService", AllowMultipleInstances = false)]
6 private AddressServiceOperations _mainPort = new AddressServiceOperations();
7
8 // The second state of this multi headed service
9 private generic.GenericState _name = new generic.GenericState();
10
11 // The alternate port used for the second service
12 [AlternateServicePort(AlternateContract = generic.Contract.Identifier)]
13 private generic.GenericServiceOperations _altPort = new generic.GenericServiceOperations ();
14

對每個端口分別實現消息處理方法,每個端口的處理方法各自維護自己的狀態對象。

1 // Service handlers for service one
2
3 /// <summary>
4 /// Get Handler
5 /// </summary>
6 /// <param name="get"></param>
7 /// <returns></returns>
8 [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
9 public virtual IEnumerator<ITask> GetAddressHandler(Get get)
10 {
11 get.ResponsePort.Post(_address);
12 yield break;
13 }
14
15 /// <summary>
16 /// Replace Handler
17 /// </summary>
18 /// <param name="replace"></param>
19 /// <returns></returns>
20 [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
21 public virtual IEnumerator<ITask> ReplaceAddressHandler(Replace replace)
22 {
23 _address = replace.Body;
24 replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
25 yield break;
26 }
27
28 // Service handlers for service two
29
30 /// <summary>
31 /// Get Handler
32 /// </summary>
33 /// <param name="get"></param>
34 /// <returns></returns>
35 [ServiceHandler(ServiceHandlerBehavior.Concurrent, PortFieldName = "_altPort")]
36 public virtual IEnumerator<ITask> GetNameHandler(generic.Get get)
37 {
38 get.ResponsePort.Post(_name);
39 yield break;
40 }
41
42 /// <summary>
43 /// Replace Handler
44 /// </summary>
45 /// <param name="replace"></param>
46 /// <returns></returns>
47 [ServiceHandler(ServiceHandlerBehavior.Exclusive, PortFieldName = "_altPort")]
48 public virtual IEnumerator<ITask> ReplaceNameHandler(generic.Replace replace)
49 {
50 _name = replace.Body;
51 replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
52 yield break;
53 }

運行服務

運行服務後,服務列表中顯示兩個實例(addressservice and addressservice/servicetutorial8.) 但是,兩個服務實例的返回狀態是不同的。

這是MRDS的服務實例中的第九個,講的的是如何實行或擴展一個通用服務協議,在實際應用中是很有 用的,因為我們不必自己定義通信的消息類型和操作類型了,直接使用微軟自己定義的協議,這樣這些服 務在VPL裡就可以變得通用了,微軟自己定義了一套協議,呼呼,他希望大家都去實現,微軟眼光很長遠 ,想在機器人領域續寫PC領域的輝煌哦……

噢耶!Your Potential!Our Passion!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved