背景
在最近几年中,越来越多的企业会将自己的网站转换成手机端的应用。这里所谓的转换,其实不是摒弃一个使用另一个,而是共存。所以就会有一个比较普遍的需求就是,很多的企业或者开发者希望使用同一套Web API来同时支持自己的网站和手机应用去操作自己的数据库,并且这个数据库的结构也是一样的。
这篇博客就是在阐述一个一模一样的情况。我的一个客户已经基于.NET Core 2.0的版本开发了一套Web API,并且网站已经在运行中。但是他想要用Xamarin.Forms来开发一个手机应用,并且是想用到Azure Mobile Apps SDK来使用离线同步(Offline Sync)功能。
当然,他希望使用同一套Web API和同一个数据库数据结构。
什么是离线同步?
如果是中文,就真的非常好理解。在使用手机的过程中,我们无法保证手机的网络信号永远是畅通的。再假设你现在在乘飞机,手机开启了飞行模式。这时候你需要在你的app中添加一些记录,比如是todoList,你当然希望一旦关闭飞行模式恢复网络之后,这些数据会被同步到数据库。这就是离线同步的意义。
看下面的微软官方解释:
Offline sync allows users to interact with a mobile application, viewing, adding, or modifying data, even where there isn’t a network connection. Changes are stored in a local database, and once the device is online, the changes can be synced with the Azure Mobile Apps instance. This article explains how to add offline sync functionality to a Xamarin.Forms application.
离线同步是如何同Xamarin以及Azure Mobile App SDK工作的?
其实非常简单,如果没有我们现在的一个特殊情况,我们可以直接使用微软官方给出的关于Azure Mobile Apps的Xamarin.Forms的template,这个我们可以从Azure portal下载到。
下载下来之后你会发现它就是一个现成的可以使用的todoList的手机应用,你可以直接按照如下的步骤来开启离线同步功能。
根据文档Create a Xamarin.Forms app with Azure的步骤来下载集成了Azure Mobile App SDK的Xamarin.Forms的项目。
根据文档Enable offline sync for your Xamarin.Forms mobile app来开启离线同步的功能。
根据Synchronizing Offline Data with Azure Mobile Apps来理解怎么使用,调试和测试离线同步的功能。
如果你跟着上面的步骤,你会发现这个sample的项目确实是可以正常工作的。
那么问题出在哪里呢?
问题就出在我的客户希望使用同一套数据库,并且也希望是使用同一套Web API来操作这个数据库的数据。
问题症状
如果仔细阅读上面第三步的那个文档的话,可以发现其实离线同步的关键代码就是调用了这个PushAsync()
方法,这个方法定义在SyncAsync()
方法中。
具体代码如下:
1 | public async Task SyncAsync() |
Wala,我的客户用了这个代码后,就在foreach循环中得到了错误,错误提示大概是:[0:] Error executing sync operation. Item: WorkDiary (fcddf2b4a5c24e8b8119be2fd3af993c). Operation discarded.
.
截图:
突破口
这个就是我这篇博客中主要想和大家分享的,是我怎么来troubleshoot这个问题,并且我是怎么找到问题根本原因的。你不会看到很多的代码层面的debugging,因为我的客户感觉比我还会调试代码。其实也是我的客户自己的调试让我很快找到了原因。
一开始做这个case的时候我确实非常迷茫,我看了客户所有和离线同步相关的那部分代码,客户基本就是跟着我们提供的sample来写的,没有私自改动过什么,除了将model object从TodoList
改成了自己的WorkDiary
之外,其他没有做过什么改动。
但是我的客户为了解决问题,自己去开发了一个LoggingHandler()
来记录调用SDK时发出的Web请求。如下:
1 | [0:] Request: POST https://xxxxxxxx.azurewebsites.net/tables/WorkDiary |
我们可以从上面的信息看到,请求的web url是什么,json格式的数据是什么,以及我们返回的response是404 not found。
调试
得到上面的信息之后,我突然之间想到,客户调用的是我们的SDK,但是客户的代码中并没有指定过往哪个地址的Web API去发送请求,我们传递的不过是要更新的数据类型,所以是不是真的他的网站和Xamarin的应用时使用了同一个Web API呢?
要检验这个其实非常简单,我们只需要抓一个Fiddler的网包看一下就知道了。
具体调试步骤如下:
首先我模拟了客户在Xamarin中发送的web请求,使用Fiddler的
Composer
的功能。我模拟了一样的数据,一样的web url,并且使用POST
的方式来发送请求。我得到了和客户的Xamarin应用一样的404 Not Found的结果:
之后我使用客户的网站来添加了一条记录,并且抓取这个过程中的Fiddler网包,结果:
并且这个web请求的数据部分是:
从上面两个Fiddler网包的对比,我们可以至少看出2点:
- 客户的网站和手机端发出去请求的目的地URL的地址完全是不同的。
- 在网站的web请求中,数据结构是Web Forms的那种表单格式,但是在使用Azure Mobile SDK的时候,是Json的数据格式。
从这两点就可以看出这个问题的根本原因了。
解决方案以及痛点
知道了根本原因之后,我找了微软的产品组来寻求帮助。结果得到的结果不是很尽人意,产品组表示,如果是使用Azure Mobile SDK的话,用户的Web API就必须要按照我们的格式来开发,不然是无法用这个SDK的。不尽人意的地方是,连一个workaround都没有。
并且,这个SDK只最高支持到.NET4.6的版本,也无法让用户改自己的.NET Core的Web API来兼容。
最后客户比较善良,愿意为了这个来开发一套新的API,之后我也有帮助客户解决另一个问题是使用这套新的API的,也确认了这样确实可以解决问题。
参考链接:
如果你想要非常详细地了解怎么将Azure Mobile SDK中的功能集成到Xamarin的应用中,那推荐看一下这个微软官方的人出的书:Develop Cloud Connected Mobile Apps with Xamarin and Microsoft Azure
评论