This repository has been archived on 2022-11-03. You can view files and clone it, but cannot push or open issues or pull requests.
DevOpsOpenHack/MobileApps/MyDriving/MyDriving.DataStore.Azure/Stores/BaseStore.cs

145 lines
4.8 KiB
C#
Raw Permalink Normal View History

2022-11-03 20:41:13 +00:00
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
using System;
using MyDriving.DataStore.Abstractions;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
using Microsoft.WindowsAzure.MobileServices.Sync;
using MyDriving.Utils;
using System.Collections.Generic;
using MyDriving.DataObjects;
using Plugin.Connectivity;
using MyDriving.AzureClient;
using MyDriving.Utils.Interfaces;
namespace MyDriving.DataStore.Azure.Stores
{
public class BaseStore<T> : IBaseStore<T> where T : class, IBaseDataObject, new()
{
IStoreManager storeManager;
IMobileServiceSyncTable<T> table;
protected IMobileServiceSyncTable<T> Table =>
table ?? (table = ServiceLocator.Instance.Resolve<IAzureClient>()?.Client?.GetSyncTable<T>());
public virtual string Identifier => "Items";
public virtual Task<bool> DropTable()
{
table = null;
return Task.FromResult(true);
}
#region IBaseStore implementation
public virtual async Task<bool> RemoveItemsAsync(IEnumerable<T> items)
{
bool result = true;
foreach (var item in items)
{
result = result && await RemoveAsync(item);
}
return result;
}
public async Task InitializeStoreAsync()
{
if (storeManager == null)
storeManager = ServiceLocator.Instance.Resolve<IStoreManager>();
if (!storeManager.IsInitialized)
await storeManager.InitializeAsync();
}
public virtual async Task<IEnumerable<T>> GetItemsAsync(int skip = 0, int take = 100, bool forceRefresh = false)
{
await InitializeStoreAsync();
if (forceRefresh)
{
await SyncAsync();
}
return await Table.ToEnumerableAsync();
}
public virtual async Task<T> GetItemAsync(string id)
{
await InitializeStoreAsync();
await SyncAsync();
var item = await Table.LookupAsync(id);
return item;
}
public virtual async Task<bool> InsertAsync(T item)
{
await InitializeStoreAsync();
await Table.InsertAsync(item); //Insert into the local store
await SyncAsync(); //Send changes to the mobile service
return true;
}
public virtual async Task<bool> UpdateAsync(T item)
{
await InitializeStoreAsync();
await Table.UpdateAsync(item); //Delete from the local store
await SyncAsync(); //Send changes to the mobile service
return true;
}
public virtual async Task<bool> RemoveAsync(T item)
{
bool result = false;
try
{
await InitializeStoreAsync();
await Table.DeleteAsync(item); //Delete from the local store
await SyncAsync(); //Send changes to the mobile service
result = true;
}
catch (Exception e)
{
Logger.Instance.Track($"Unable to remove item {item.Id}:{e}");
}
return result;
}
//Note: do not call SyncAsync with ConfigureAwait(false) because when the authentication token expires,
//the thread running this method needs to open the Login UI.
//Also in the method which calls SyncAsync, do not use ConfigureAwait(false) before calling SyncAsync, because once ConfigureAwait(false) is used
//in the context of an async method, the rest of that method's code may also run on a background thread.
public virtual async Task<bool> SyncAsync()
{
if (!CrossConnectivity.Current.IsConnected)
{
Logger.Instance.Track("Unable to sync items, we are offline");
return false;
}
try
{
var client = ServiceLocator.Instance.Resolve<IAzureClient>()?.Client;
if (client == null)
{
Logger.Instance.Track("Unable to sync items, client is null");
return false;
}
//push changes on the sync context before pulling new items
await client.SyncContext.PushAsync();
await Table.PullAsync($"all{Identifier}", Table.CreateQuery());
}
catch (Exception ex)
{
Logger.Instance.Track("SyncAsync: Unable to push/pull items: " + ex.Message);
return false;
}
return true;
}
#endregion
}
}