在 Xamarin.Form 使用 ProtoBuf, 提升APP的体验档次

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 不支持这样的功能, 那真是有辱谷歌的大牙了.
后来看到 AsReferenceDefault 这个东西, 敲了一下, 没有这个属性, 才意思到下载的版本太老了.

服务端的数据实体定义:

1     [ProtoContract(AsReferenceDefault = true, ImplicitFields = ImplicitFields.AllFields)]
2     public partial class T_BRANCH
3     {
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     }

至此, 服务端完成了, 可以请求一下试试效果. 记得要加请求头: 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 的全部过程.

时间: 2024-08-30 01:22:54

在 Xamarin.Form 使用 ProtoBuf, 提升APP的体验档次的相关文章

Xamarin.Form 项目总结

离上一篇 用Xamarin.Form做个技术预览版的APP  有一个月零几天了. 现在这个APP在业务方面的代码由另外一个同事全权处理, 我又闲了下来, 要去弄另外一个项目. 这个把月, 踩过 Xamarin.Form 很多坑, 填过很多坑, 也造了很坑... 这里做个总结, 给想跳坑的你做个参考. ListView 的下拉刷新 下拉刷新还是很简单的, 首先要设置 listView.IsPullToRefreshEnabled 为 true 当下刷新时, RefreshCommand 会被调用,

FlipView For Xamarin.Form 之 IOS

之前写过两篇博文 是关于 Android 和 Windows Phone 下的 FlipView 的实现. 上上周,有个印度佬通过 GitHub 找到我, 问我有没有打算个 ios 端的,还说比较了相同功能的几个开源项目,我的这个项目值得推荐.说的我心潮澎湃,上周末花了一个周末升级到最新的 XCode 7,顺便也升级到了 OS X EI Capitan, 安装了最新的 Xamarin, 使用了 IOS 9 提供的免费证书,终于于今天凌晨1点(10月25)把 ios 端的 renderer 给写出

Xamarin.Form 实例: Discuz BBS 客户端 源码分享

感谢台风, 这个十一长假让我好好的休息了一回, 睡觉到腰酸背疼, 看电影看到眼发红. 今天最后一天, 不敢出去逛, 不知道哪会还会下暴雨... 嗯嗯..这个项目其实在十一之前就开始了, 工作无聊,没有新任务, 我就搞起它. 至于为什么选 Discuz 的 BBS , 因为我常上的几个网站, 都有一堆的 APP , 官方的, 第三方的 . BBS 虽然已经没落了, 但是官方的 APP 居然用不了! 写这个东西之前, 本来想拿来看 1024 的, 但是 1024 要么不是最新版本, 要么禁用了 AP

Xamarin.Form 蓝牙ble

本文介绍Xamarin.Form的蓝牙使用方法,开始之前说说题外话,就Xamarin.Form来说,在国内是没多少人在弄的,但对于我自己来说,是吃了这碗饭,也希望在这行做的人越来越多,越来越好,本人2016年开始入使用Xamarin.Form开发App,那时候刚微软刚收购Xamarin,也正式开源免费给开发者使用,但那时候的本说实话是有多不完善的,直到现在微软依然有很多不完善的功能,所以在国内学这个,一般是由公司高层推这个技术,直接至底向上的非常少.微软的东西在国内环境来说,多不太好,很多大的互

Xamarin.Form指纹认证

Xamarin.Form框架并没有提供指纹认证功能,需要分平台实现! Android的Fingerprint Authentication 参考:https://docs.microsoft.com/zh-cn/xamarin/android/platform/fingerprint-authentication/ 概述 指纹扫描仪在Android设备上的到来为应用程序提供了用户身份验证的传统用户名/密码方法的替代方案. 使用指纹对用户进行身份验证可以使应用程序合并比用户名和密码更不安全的安全性

Xamarin.Form 下拉刷新动画

好像园子里对 Xamarin 感兴趣的人很少啊... 来, 先给各位爷们逗个笑, 本山大爷本色出演: 照例, 上源码: https://github.com/gruan01/ListViewExtend 目前只有 WP 的效果, Android 还在研究, IOS 的还没计划. ------------------------------------------------------ Xamarin.Form 的 ListView 只支持下拉刷新 (这里有用法), 上拉 加载更多 没有对应的事

极光开发者沙龙 之 移动应用性能优化实践 【一】旧酒新瓶——换个角度提升 App 性能与质量

旧酒新瓶--换个角度提升 App 性能与质量 主讲人:高亮亮 ---   饿了么移动技术部高级iOS工程师,负责饿了么商家版iOS APP开发,对架构和系统底层有深入研究,擅长移动性能分析,trouble shooting,iOS 逆向编程. 主讲时间:2017-05-26 主讲内容: 1.性能与质量概述: 2."新"技术概念的介绍与实践: 3.违反常规的"真理": 一.性能与质量概述: ? 应用分级以及与性能质量的关系 ? 根据设备特点设计提升方案 ? 结合主要业

挣扎着写 FlipView For Xamarin.Form

Xamarin.Form 中没有 FlipView, 也没有 CarouselView , 有的只是一个 CarouselPage, 它是一个 Page, 不是一个 View ! Windows Phone 8.1 下有个控件叫 FlipView, 但是它不存于在 WP Siliverlight ! 而Xamarin.Form 的 WP 项目又是基于 WP Siliverlight 的. Android 原生也没有 FlipView 类似的控件. IOS 下冒似也没有. 我急切的想弄一个这样的东

Xamarin.Form 初学 之 服务引用-WCF服务引用

最近研究一下Xamarin.Form,感觉这个东西确实不错,之前一直做WPF相关,然后看到Xamarin.Form开发与WPF特别相似的语法.很有兴趣! 可是环境部署对于小白的我,可是费了不少功夫!安装VS2015费了我好些时间!安装部署以后再说!先说说引用WCF服务的坑吧! 官方文档:Xamarin可以调用WCF,可以怎么调用???(满脑子问号)https://developer.xamarin.com/guides/xamarin-forms/web-services/consuming/w