尝试与Azure移动服务同步时,IMobileServiceClient.PullAsync死锁

我有以下课程。

public class AzureMobileDataContext : IAsyncInitialization { private static readonly Lazy lazy = new Lazy (() => new AzureMobileDataContext( new MobileServiceClient( "http://myservice.azure-mobile.net/", "123456789ABCDEFGHIJKLMNOP"))); public static AzureMobileDataContext Instance { get { return lazy.Value; } } public Task Initialization { get; private set; } public IMobileServiceClient Context { get; private set; } private Object lockObj = new Object (); private static MobileServiceSQLiteStore store; public AzureMobileDataContext (IMobileServiceClient context) { Context = context; Initialization = Init (); Initialization.ContinueWith (async (antecedent) => { await Context.SyncContext.InitializeAsync (store, new MobileServiceSyncHandler ()); }); } private Task Init () { return Task.Run (() => { lock (lockObj) { if (!Context.SyncContext.IsInitialized) { try { store = new MobileServiceSQLiteStore ("mysqlite.db3"); store.DefineTable (); store.DefineTable (); store.DefineTable (); store.DefineTable (); store.DefineTable (); } catch (Exception ex) { Debug.WriteLine ("Init: {0}", ex.Message); } } } }); } public async Task<IMobileServiceSyncTable> GetTableAsync () { await Initialization; return Context.GetSyncTable (); } public async Task PushAsync () { try { await Initialization; await Context.SyncContext.PushAsync (); } catch (MobileServiceInvalidOperationException invalidOperationEx) { Debug.WriteLine (invalidOperationEx.Message); } catch (MobileServicePushFailedException pushFailedException) { Debug.WriteLine (pushFailedException.Message); } } public async Task PullAsync (IMobileServiceTableQuery query) { try { await Initialization; IMobileServiceSyncTable entityTable = await GetTableAsync (); await entityTable.PullAsync (typeof(TEntity).ToString (), query); // Never returns, no exception is caught or thrown. await entityTable.PurgeAsync (); } catch (MobileServiceInvalidOperationException preconditionFailedEx) { Debug.WriteLine (preconditionFailedEx.Message); } catch (Exception ex) { Debug.WriteLine (ex.Message); } } public async Task SyncAsync () { await PushAsync (); IMobileServiceSyncTable syncTable = await GetTableAsync (); await PullAsync (syncTable.CreateQuery ()); } } 

我在BaseRepository中使用这个单例,我有5个不同的实体存储库的基类。

 public abstract class BaseRepository : IRepository where TEntity : class { protected AzureMobileDataContext MobileServiceContext { get { return AzureMobileDataContext.Instance; } } protected virtual Task PushAsync () { return MobileServiceContext.PushAsync (); } protected virtual Task PullAsync (IMobileServiceTableQuery query) { return MobileServiceContext.PullAsync (query); } public virtual async Task<DataObjectResponse<IEnumerable>> FindAsync (Expression<Func> predicate) { IMobileServiceSyncTable syncTable = await MobileServiceContext.GetTableAsync (); await PullAsync (syncTable.CreateQuery ()); IEnumerable entities = await syncTable.Where (predicate).ToEnumerableAsync (); return new DataObjectResponse<IEnumerable> (entities); } } 

用户存储库。

 public class UsersAzureRepository : BaseRepository, IUsersRepository { public UsersAzureRepository () { } public async Task<DataObjectResponse> FindByIdAsync (string entityId) { DataObjectResponse<IEnumerable> users = await FindAsync (p => p.Id == entityId); return new DataObjectResponse(users.Data.FirstOrDefault ()); } } 

包含GetUserById方法的DataService Facade类。

 public async Task GetUserById (string userId) { DataObjectResponse users = await UsersRepository.FindByIdAsync (userId); UserModel userModel = Mapper.Map (users.Data); return userModel; } 

用户查看模型方法。

 public async Task GetUsersAsync() // testing purposes { UserModel user = await _dataService.GetUserById("032beb3b-1cbf-4a0d-809c-a25c71139c55"); if (user != null) { Debug.WriteLine ("User loaded: {0}", user.Id); } return user; } 

从iOS UIViewController调用。

 public async override void ViewDidLoad () { base.ViewDidLoad (); UserModel user = await ViewModel.GetUsersAsync (); } 

AzureMobileDataContext更多地作为IMobileServiceClient上下文操作的线程安全包装器,确保不会有多个线程尝试初始化数据库(我之前直接将它用于BaseRepository时有一个例外)。

我不太确定问题出在哪里。 我怀疑包装器不是最好的解决方案,欢迎任何建议。

调试PullAsync方法的其他任何方法?

[编辑]

本地SQLite数据库同步来自远程服务的表数据,但仍然不会返回调用。

问题出在Azure Mobile Service,服务器端。

我从TableController返回一个IEnumerable,但SDK使用OData查询表达式来完成它自己的工作,返回一个IEnumerable是不够的,改为IQueryable修复了这个拉动数据时连续循环的问题。

我坚信服务器返回类型不应该与SDK相关,但这是它的工作方式。