Microsoft Robotics Developer Studio (MRDS) 採用 DSS (Decentralized Software Services) 架構,服務間透過通用服務合約 實現互通。本文基於 Service Tutorial 9 (C#),詳細說明三種實作策略:直接實作、擴展合約、多頭服務,並附完整程式碼關鍵點解析。
Samples\ServiceTutorials\Tutorial9\CSharp*Proxy.dll (位於 MRDS 安裝目錄 bin),定義通用合約:GenericState、GenericServiceOperations、Contract.Identifier。服務名:GenericServiceImplementation。不定義自身狀態與操作,完全委派給通用合約。
public sealed class Contract {
public const String Identifier = "https://schemas.tempuri.org/2007/08/servicetutorial9/genericservice/implementation.html";
}
using generic = ServiceTutorial8.Proxy;[Contract(Contract.Identifier)]
[AlternateContract(generic.Contract.Identifier)] // 宣告支援通用合約
[DisplayName(...)]
[Description(...)]
public class ImplementationService : DsspServiceBase
[ServiceState] private generic.GenericState _state = new generic.GenericState();
[ServicePort("/GenericServiceImplementation", AllowMultipleInstances = false)]
private generic.GenericServiceOperations _mainPort = new generic.GenericServiceOperations();
[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public virtual IEnumerator GetHandler(generic.Get get) {
get.ResponsePort.Post(_state);
yield break;
}
服務目錄顯示兩個服務節點:genericserviceimplementation 與 genericserviceimplementation/servicetutorial8,**狀態與操作完全相同**,後者為通用合約的標準投影。
服務名:GenericServiceExtension。保留通用合約功能,同時新增自有狀態 (Age) 與操作 (UpdateAge),實現向後相容與功能擴展並存。
[DataContract]
public class ExtensionState : generic.GenericState {
private int _age;
[DataMember] public int Age { get { return _age; } set { _age = value; } }
// 從基底狀態建構 (用於 Replace 通用操作)
internal ExtensionState(generic.GenericState state) {
this.FirstName = state.FirstName;
this.LastName = state.LastName;
this.Age = -1;
}
// 顯式轉換為基底狀態 (用於 Get 通用操作回傳)
internal generic.GenericState ToGenericState() {
var gen = new generic.GenericState();
gen.FirstName = this.FirstName;
gen.LastName = this.LastName;
return gen;
}
}
UpdateAge 至 PortSet。
[ServicePort]
public class GenericServiceExtensionOperations : PortSet { }
AlternateServicePort) 掛載通用操作。
// 主連接埠 (擴展)
[ServicePort("/GenericServiceExtension", AllowMultipleInstances = false)]
private GenericServiceExtensionOperations _mainPort = new GenericServiceExtensionOperations();
// 備用連接埠 (通用)
[AlternateServicePort(AlternateContract = generic.Contract.Identifier)]
private generic.GenericServiceOperations _altPort = new generic.GenericServiceOperations();
注意:AlternateContract(用於類別) 與AlternateServicePort(用於連接埠) **不可同時使用**。若主連接埠即為通用操作,用前者;若主連接埠為擴展操作,通用操作置於備用連接埠,用後者。
PortFieldName = "_altPort"。
[ServiceHandler(ServiceHandlerBehavior.Concurrent, PortFieldName = "_altPort")]
public virtual IEnumerator GenericGetHandler(generic.Get get) {
get.ResponsePort.Post(_state.ToGenericState()); // 回傳基底狀態
yield break;
}
服務目錄顯示 genericserviceextension (含 Age 與 UpdateAge) 與 genericserviceextension/servicetutorial8 (僅通用狀態與操作) **狀態結構不同**,後者可被僅知通用合約的消費者透明使用。
服務名:MultiFunctionService。單一服務進程內承載多個獨立狀態與連接埠 (AddressService + 通用 NameService),外觀上如同多個獨立服務,內部可共享資源或高耦合邏輯。
// 狀態 1 + 主連接埠
private AddressState _address = new AddressState();
[ServicePort("/AddressService", AllowMultipleInstances = false)]
private AddressServiceOperations _mainPort = new AddressServiceOperations();
// 狀態 2 + 備用連接埠 (通用合約)
private generic.GenericState _name = new generic.GenericState();
[AlternateServicePort(AlternateContract = generic.Contract.Identifier)]
private generic.GenericServiceOperations _altPort = new generic.GenericServiceOperations();
各連接埠對應獨立處理器 (GetAddressHandler/ReplaceAddressHandler、GetNameHandler/ReplaceNameHandler),各自維護自己的狀態實例。服務目錄顯示 addressservice 與 addressservice/servicetutorial8,**回傳狀態型別不同**。
| 策略 | 適用場景 | 耦合度 | 彈性 |
|---|---|---|---|
| 直接實作 | 需完全符合標準合約,無額外功能 | 低 (僅依賴合約) | 低 |
| 擴展合約 | 需相容現有消費者,同時提供新功能 | 中 (基底合約穩定) | 高 |
| 多頭服務 | 多個緊密相關功能需共享進程/資源 | 高 (內部耦合) | 中 (建議評估拆分為獨立服務) |
MRDS 定義通用合約旨在建立機器人服務生態標準,透過 VPL (Visual Programming Language) 實現拖曳式組合。掌握三種實作模式,是開發可互操作機器人服務的關鍵。