在 Xamarin.Form 使用 ProtoBuf, 提升APP的體驗檔次

來源:互聯網
上載者:User

標籤:

XML被JSON代替的時候,是因為JSON的更小的檔案體積.
現在移步到手機,json 資料包也愈發顯的不可接受了.滿眼的都是 json 的屬性名稱,真正有用的屬性值卻只佔整個JSON包的一小部份.如果能不要"屬性名稱",那可太好了,但是那是不可能的.

老早就聽說過 ProtoBuf ,一直沒有用過.這兩天耗了些時間研究了一下,成功的應用於服務端(WebApi) 和 用戶端(Xamarin.Form) 上.
先貼兩張圖感受一下:

 

能小多少,和具體的類結構及資料完整性有關. 不過單從這份結果對比來看, 效果真的很吸引人! 

如果將它應用於手機端, 可以給你的APP體驗抬高不止一個檔次!

 

1, 服務端實體類的聲明 (WebApi):

NuGet -> ProtoBuf-net, 要安新版本的.
一開始, 我直接安裝的 WebApiContrib.Formatting.ProtoBuf, 順帶安裝 protobuf-net 2.0.0.448 版的, 結果在有循環參考的實體集上報錯:
Possible recursion detected.

為什麼會有循環參考? 你用過 EF嗎? 搜了一圈, 有說什麼 protobuf 只支援 Tree ,不支援圖的.
Json.Net 序列化的時候,可以設定 LoopReferences = Ignore, 如果 protobuf 不支援這樣的功能, 那真是有辱Google的大牙了.
後來看到 AsReferenceDefault 這個東西, 敲了一下, 沒有這個屬性, 才意思到下載的版本太老了.

 

服務端的資料實體定義:

1     [ProtoContract(AsReferenceDefault = true, ImplicitFields = ImplicitFields.AllFields)]2     public partial class T_BRANCH3     {4         public decimal BRANCH_ID { get; set; }5     6         public string BRANCH_CODE { get; set; }7 ...

ImplicitFields.AllFields 的功效等於在每個屬性上加 ProtoMember.

 

2, 註冊 Protobuf 格式器

在 Global 裡添加:

1 GlobalConfiguration.Configuration.Formatters.Add(new ProtoBufFormatter());

ProtoBufFormatter 的源碼:

 1     public class ProtoBufFormatter : MediaTypeFormatter { 2         private static readonly MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/x-protobuf"); 3         private static Lazy<RuntimeTypeModel> model = new Lazy<RuntimeTypeModel>(CreateTypeModel); 4  5         public static RuntimeTypeModel Model { 6             get { 7                 return model.Value; 8             } 9         }10 11         public ProtoBufFormatter() {12             SupportedMediaTypes.Add(mediaType);13         }14 15         public static MediaTypeHeaderValue DefaultMediaType {16             get {17                 return mediaType;18             }19         }20 21         public override bool CanReadType(Type type) {22             return CanReadTypeCore(type);23         }24 25         public override bool CanWriteType(Type type) {26             return CanReadTypeCore(type);27         }28 29         public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger) {30             var tcs = new TaskCompletionSource<object>();31 32             try {33                 object result = Model.Deserialize(stream, null, type);34                 tcs.SetResult(result);35             } catch (Exception ex) {36                 tcs.SetException(ex);37             }38 39             return tcs.Task;40         }41 42         public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext) {43             var tcs = new TaskCompletionSource<object>();44 45             try {46                 Model.Serialize(stream, value);47                 tcs.SetResult(null);48             } catch (Exception ex) {49                 tcs.SetException(ex);50             }51 52             return tcs.Task;53         }54 55         private static RuntimeTypeModel CreateTypeModel() {56             var typeModel = TypeModel.Create();57             typeModel.UseImplicitZeroDefaults = false;58             return typeModel;59         }60 61         private static bool CanReadTypeCore(Type type) {62             return true;63         }64     }
View Code

 

至此, 服務端完成了, 可以請求一下試試效果. 記得要加要求標頭: Accept ,值為:application/x-protobuf

 

3, PCL 實體類

一般,我都會將資料實體(POCO)單獨分隔成一個類庫, 方便各個項目使用, 因為這些POCO類庫不涉及任何商務邏輯.

現在,在手機端遇到了一個問題, 用這些類庫,將伺服器上收到的資料還原序列化,無論是 json 還是 protobuf , 都會報錯.

跟蹤了一下, 大至都是因為 : 加到類上的 Serializable;  加到屬性上的 Required/StringLength 等 特性 造成的. 因為這些特性在 PCL 類庫裡是不受支援的.

將這些東西去掉當然是不可能的, 那怎麼辦呢 ?

如果是基於DbFirst / ModelFirst 的 EF 類庫,那好辦, 新增一個對應的PCL類庫, 把 原庫下面的 TT 模板複製一份到PCL庫中, 改一下就可以了.

如果是 CodeFirst 的類庫 , 那就有點小複雜:

1, 還是建立一個對應的 PCL 類庫.

2, 將原庫中的所有類檔案都複製一份到PCL類庫中.

3, 添加一個 attributes 目錄, 將類庫中所有用到的,不被PCL支援的特性 重新定義一遍, 比如 StringLengthAttribute:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6  7 namespace System.ComponentModel.DataAnnotations { 8     public class StringLengthAttribute : Attribute { 9 10         public StringLengthAttribute(int max) {11         }12 13     }14 }

注意, 命名空間一定要和原來的一樣.

 

4, 將這些PCL類庫拿去代替原庫,在手機中使用.

 

4, 手機端的 protobuf 類庫

Protobuf-net 是有 PCL 版本的, 只不過在 NuGet 中添加的 Protobuf-net 是無法安裝到 PCL 庫中的, 需要先把 Protobuf-net 下載來, 然後手工添加引用:

不要添加非 PCL 版的 protobuf-net 到 PCL 類庫中, 運行會報錯.

 

5, WebApi Client 設定

1,添加上面的 ProtoBufFormatter.cs 到手機端的PCL類庫中.

2, 在 ReadAsAsync 方法中使用 ProtoBufFormatter :

 1             var a = await this.GetResult(token); 2             var reason = ""; 3             HttpStatusCode? status = null; 4             if (a != null) { 5                 if (a.IsSuccessStatusCode) { 6                     if (this.SupportProtoBuf) { 7                         return await a.Content.ReadAsAsync<T>(new[] { new ProtoBufFormatter() }); 8                     } else 9                         return await a.Content.ReadAsAsync<T>();10                 } else {11                     reason = a.ReasonPhrase;12                     status = a.StatusCode;13                 }14             }

具體請參考: 

https://github.com/gruan01/LbcTest/blob/master/Lbc.WebApi/MethodBase.cs

 

 

OK, 以上是在 Xamarin.Form 中使用 Protobuf 的全部過程.

在 Xamarin.Form 使用 ProtoBuf, 提升APP的體驗檔次

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.