在新版本的Beetle.NetPackage中提供了對Protobuf和Controller的支援,所以在WP8下使用Beetle.NetPackage進行基於TCP的資料互動則一件非常簡單事情.下面通過元件在WP8下簡單實現基於TCP通訊的訂單線上查詢功能.
協議定義
為了簡化互動資料的處理在這裡使用Protobuf來描述資料互動,通過Protobuf制訂一系列的請求和應答物件來代替平常在TCP下繁瑣的資料流處理過程.下面通過Protobuf來描述訂單查詢的通訊協議.
1 [ProtoContract] 2 public class GetCustomer 3 { 4 [ProtoMember(1)] 5 public string Name { get; set; } 6 } 7 8 [ProtoContract] 9 public class GetCustomerResponse 10 { 11 12 [ProtoMember(1)] 13 public IList<Customer> Items 14 { 15 get; 16 set; 17 } 18 19 } 20 21 [ProtoContract] 22 public class Customer 23 { 24 [ProtoMember(1)] 25 public string ID 26 { 27 get; 28 set; 29 } 30 [ProtoMember(2)] 31 public string Name 32 { 33 get; 34 set; 35 } 36 public override string ToString() 37 { 38 return Name; 39 } 40 } 41 42 [ProtoContract] 43 public class GetEmployee 44 { 45 [ProtoMember(1)] 46 public string Name { get; set; } 47 } 48 49 [ProtoContract] 50 public class GetEmployeeResponse 51 { 52 [ProtoMember(1)] 53 public IList<Employee> Items 54 { 55 get; 56 set; 57 } 58 } 59 60 [ProtoContract] 61 public class Employee 62 { 63 64 [ProtoMember(1)] 65 public string ID 66 { 67 get; 68 set; 69 } 70 [ProtoMember(2)] 71 public string Name 72 { 73 get; 74 set; 75 } 76 public override string ToString() 77 { 78 return Name; 79 } 80 81 } 82 83 [ProtoContract] 84 public class OrderSearch 85 { 86 [ProtoMember(1)] 87 public string Employee { get; set; } 88 [ProtoMember(2)] 89 public int PageIndex { get; set; } 90 [ProtoMember(3)] 91 public string Customer { get; set; } 92 [ProtoMember(4)] 93 public string FromDate { get; set; } 94 [ProtoMember(5)] 95 public string ToDate { get; set; } 96 } 97 98 [ProtoContract] 99 public class OrderSearchResponse 100 { 101 [ProtoMember(1)] 102 public IList<Order> Items 103 { 104 get; 105 set; 106 } 107 [ProtoMember(2)] 108 public int PageIndex 109 { 110 get; 111 set; 112 } 113 [ProtoMember(3)] 114 public int Pages 115 { 116 get; 117 set; 118 } 119 } 120 121 [ProtoContract] 122 public class Order 123 { 124 [ProtoMember(1)] 125 public string OrderID { get; set; } 126 [ProtoMember(2)] 127 public string Employee { get; set; } 128 [ProtoMember(3)] 129 public string Customer { get; set; } 130 [ProtoMember(4)] 131 public string OrderDate { get; set; } 132 [ProtoMember(5)] 133 public string RequiredDate { get; set; } 134 [ProtoMember(6)] 135 public string ShippedDate { get; set; } 136 [ProtoMember(7)] 137 public string ShipName { get; set; } 138 [ProtoMember(8)] 139 public string ShipAddress { get; set; } 140 [ProtoMember(9)] 141 public string ShipCity { get; set; } 142 [ProtoMember(10)] 143 public string ShipRegion { get; set; } 144 } 145 146 [ProtoContract] 147 public class GetOrderDetail 148 { 149 [ProtoMember(1)] 150 public string OrderID { get; set; } 151 } 152 153 [ProtoContract] 154 public class GetOrderDetailResponse 155 { 156 [ProtoMember(1)] 157 public IList<OrderDetail> Items 158 { 159 get; 160 set; 161 } 162 } 163 164 [ProtoContract] 165 public class OrderDetail 166 { 167 [ProtoMember(1)] 168 public string OrderID { get; set; } 169 [ProtoMember(2)] 170 public string Product { get; set; } 171 [ProtoMember(3)] 172 public double UnitPrice { get; set; } 173 [ProtoMember(4)] 174 public int Quantity { get; set; } 175 [ProtoMember(5)] 176 public float Discount { get; set; } 177 }
由於這裡使用了protobuf-net,所以通過類和特性來結合,其實規範方便其他平臺處理還是建議使用proto檔案描述來生成對應的類,這樣可以方便生成C++,JAVA等不同平臺的互動物件.
定義TCP通訊物件
通過Beetle.NetPackage對protobuf的支援,在WP8下建立相應的TCP通訊是件非常簡單的事情.
1 Beetle.NetPackage.ProtoPakcage.Register(typeof(MainPage).Assembly); 2 if (mClient == null) 3 { 4 mClient = new Beetle.NetPackage.NetClient("192.168.0.104", 9088, new Beetle.NetPackage.ProtoPakcage(), this); 5 mClient.LittleEndian = false; 6 } 7 mClient.Connect();
在使用protobuf前通過ProtoPakcage.Register把程式集下面對應的protobuf訊息註冊到元件中,然後建立相應的NetClient就可以進行資料通訊.在這裡為了和android互動相容把client的LittleEndian屬性設定成false即在處理資料過程採用高字序作為一些資料型別的處理方式.
訊息路由分發
在新版本的Beetle.NetPackage中提供簡單的訊息路由功能,因此在編寫訊息接收處理的時候再也不需要通過if來判斷不同訊息去呼叫方法.使用訊息路由並不需開發人員定義複雜的訊息規則,只需要定義相應訊息型別的引數即可讓元件幫助完成這個事情.
1 public void OnSearchOrderResponse(Beetle.NetPackage.NetClient client, OrderSearchResponse e) 2 { 3 if (e.Items == null) 4 lstOrders.ItemsSource = null; 5 else 6 lstOrders.ItemsSource = e.Items.ToList(); 7 mPageIndex = e.PageIndex; 8 mPages = e.Pages; 9 } 10 11 public void OnGetEmployee(Beetle.NetPackage.NetClient client, GetEmployeeResponse e) 12 { 13 mEmployees = e.Items; 14 lstEmployee.ItemsSource = e.Items.ToList(); 15 } 16 public void OnGetCustomer(Beetle.NetPackage.NetClient client, GetCustomerResponse e) 17 { 18 mCustomers = e.Items; 19 lstCustomer.ItemsSource = e.Items.ToList(); 20 21 } 22 public void OnGetOrderDetail(Beetle.NetPackage.NetClient client, GetOrderDetailResponse e) 23 { 24 DialogOrderDetail detail = new DialogOrderDetail(); 25 CustomMessageBox mOrderDetailDialog = new CustomMessageBox 26 { 27 Content = detail, 28 Title = "OrderDetail", 29 RightButtonContent = "OK" 30 }; 31 detail.ListSelector.ItemsSource = e.Items.ToList(); 32 mOrderDetailDialog.Show(); 33 }
以上是制定不同訊息的處理過程,在接收訊息的時候觸發這些過程只需要簡單地呼叫Controller.Invoke方法即可完成.
1 public void ClientReceive(Beetle.NetPackage.NetClient client, object message) 2 { 3 this.Dispatcher.BeginInvoke(() => 4 { 5 Beetle.NetPackage.Controller.Invoke(this, mClient, message); 6 }); 7 }
在訊息接收方法中呼叫Controller.Invoke元件會自動匹配相應訊息處理的方法並呼叫,由於是元件自動匹配所以在制定方法的過程也需要遵循一個規則,就是在一個物件中對應訊息處理的方法必須是唯一的.
執行效果
總結
通過Beetle.NetPackage只需要很少量的程式碼就能完成基於TCP的物件資料互動處理,而開發者是完全不用關心下層的協議處理細節,Beetle.NetPackage不僅僅提供對wp8的支援,還提供對flash和android的支援.