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

时间:2015-07-21 00:13:03

标签: ios xamarin async-await deadlock azure-mobile-services

我有以下课程。

public class AzureMobileDataContext : IAsyncInitialization
    {
        private static readonly Lazy<AzureMobileDataContext> lazy =
            new Lazy<AzureMobileDataContext> (() => 
                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<Post> ();
                            store.DefineTable<PostPhotoUrl> ();
                            store.DefineTable<User> ();
                            store.DefineTable<Club> ();
                            store.DefineTable<District> ();
                        } catch (Exception ex) {
                            Debug.WriteLine ("Init: {0}", ex.Message);
                        }
                    }
                }
            });
        }

        public async Task<IMobileServiceSyncTable<TEntity>> GetTableAsync<TEntity> ()
        {
            await Initialization;
            return Context.GetSyncTable<TEntity> ();
        }

        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<TEntity> (IMobileServiceTableQuery<TEntity> query)
        {
            try {
                await Initialization;
                IMobileServiceSyncTable<TEntity> entityTable = await GetTableAsync<TEntity> ();
                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<TEntity> ()
        {
            await PushAsync ();
            IMobileServiceSyncTable<TEntity> syncTable = await GetTableAsync<TEntity> ();
            await PullAsync (syncTable.CreateQuery ());
        }
    }

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

public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected AzureMobileDataContext MobileServiceContext { get { return AzureMobileDataContext.Instance; } }

        protected virtual Task PushAsync ()
        {
            return MobileServiceContext.PushAsync ();
        }

        protected virtual Task PullAsync (IMobileServiceTableQuery<TEntity> query)
        {
            return MobileServiceContext.PullAsync (query);
        }

        public virtual async Task<DataObjectResponse<IEnumerable<TEntity>>> FindAsync (Expression<Func<TEntity, bool>> predicate)
        {
            IMobileServiceSyncTable<TEntity> syncTable = await MobileServiceContext.GetTableAsync<TEntity> ();
            await PullAsync (syncTable.CreateQuery ());
            IEnumerable<TEntity> entities = await syncTable.Where (predicate).ToEnumerableAsync ();
            return new DataObjectResponse<IEnumerable<TEntity>> (entities);
        }
}

用户存储库。

public class UsersAzureRepository : BaseRepository<User>, IUsersRepository
    {
        public UsersAzureRepository ()
        {
        }

        public async Task<DataObjectResponse<User>> FindByIdAsync (string entityId)
        {
            DataObjectResponse<IEnumerable<User>> users = await FindAsync (p => p.Id == entityId);
            return new DataObjectResponse<User>(users.Data.FirstOrDefault ());
        }
    }

包含GetUserById方法的DataService Facade类。

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

用户查看模型方法。

public async Task<UserModel> 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上下文操作的线程安全包装器,确保不会有多个线程尝试初始化数据库(直接将它用于{{时我有一个例外) 1}}之前)。

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

调试BaseRepository<T>方法的其他任何方法?

[编辑]

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

0 个答案:

没有答案