Я пытаюсь выполнить автономную синхронизацию с приложением Xamarin, созданным с помощью шаблонов в Visual Studio. Синхронизация работала, пока я не добавил поля DateTime. Кажется, DateTime неправильно интерпретируется кодом Xamarin или Sqlite. Это, безусловно, проблема правильной интерпретации значения DateTime, отправленного с сервера, но как это можно решить? Я новичок в Xamarin и Sqlite, поэтому я не понимаю, в чем проблема. Проблема возникает во время линии
await ClientServiceManager.ClientServiceManagerDefault.InspectionsTable.PullAsync("allInspections", _inspectionsTable.CreateQuery());
работает, но так как это скрыто в библиотеке классов, я не могу перейти к отладке.
Данные в базе данных выглядят нормально (например, см. Выделенную дату создания):
Fiddler сообщает о следующем json, отправленном в мобильное приложение:
Таблица базы данных Sqllite, сгенерированная хранилищем данных, выглядит следующим образом:
После синхронизации данные не будут читаться в базе данных Sqlite, если вы попытаетесь запросить их, используя select id, createddate from inspection
:
System.FormatException: String was not recognized as a valid DateTime.
Если я выполню запрос select id, cast(createddate as text) from inspection
, значение результата, отображаемое для созданной даты, будет 1525165956.457.
Синхронизация запускается через вызов PullAsync, показанный ниже:
public class ClientServiceManager
{
IMobileServiceSyncTable<InspectionItem> _inspectionItemsTable;
IMobileServiceSyncTable<Inspection> _inspectionsTable;
MobileServiceClient _client;
public MobileServiceClient CurrentClient
{
get { return _client; }
}
public static ClientServiceManager ClientServiceManagerDefault { get; set; } = new ClientServiceManager();
public IMobileServiceSyncTable<InspectionItem> InspectionItemsTable
{
get { return _inspectionItemsTable; }
}
public IMobileServiceSyncTable<Inspection> InspectionsTable
{
get { return _inspectionsTable; }
}
public ClientServiceManager()
{
_client = new MobileServiceClient(App.AzureMobileAppUrl)
{
SerializerSettings = new MobileServiceJsonSerializerSettings
{
CamelCasePropertyNames = true
}
};
var path = Path.Combine(MobileServiceClient.DefaultDatabasePath, "syncstore.db");
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<Inspection>();
store.DefineTable<InspectionItem>();
_client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
_inspectionItemsTable = _client.GetSyncTable<InspectionItem>();
_inspectionsTable = _client.GetSyncTable<Inspection>();
}
public async Task<bool> SyncAsync()
{
try
{
Debug.WriteLine($"SyncAsync called. Need to sync {_client.SyncContext.PendingOperations} changes.");
//Pull server table changes to local tables.
await ClientServiceManager.ClientServiceManagerDefault.InspectionsTable.PullAsync("allInspections", _inspectionsTable.CreateQuery());
await ClientServiceManager.ClientServiceManagerDefault.InspectionItemsTable.PullAsync("allInspectionItems", _inspectionItemsTable.CreateQuery());
//Push all context changes to the server.
await _client.SyncContext.PushAsync();
}
catch (MobileServicePushFailedException exc)
{
Debug.WriteLine($"MobileServicePushFailedException occurred. Inner exception: {exc.InnerException}");
if (exc.PushResult == null)
{
Debug.WriteLine($"Unable to sync, which is alright since we have offline capabilities: {exc.Message}");
return false;
}
foreach (var error in exc.PushResult.Errors)
{
if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
{
//Update failed, reverting to server's copy.
await error.CancelAndUpdateItemAsync(error.Result);
}
else
{
// Discard local change.
await error.CancelAndDiscardItemAsync();
}
Debug.WriteLine($"Error executing sync operation. Item: {error.TableName} ({error.Item["id"]}). Operation discarded.");
}
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to sync items: {ex.Message}");
return false;
}
return true;
}
}
Кроме того, таблица сущностей основана на этом классе, где вы видите используемые типы данных:
using System;
#if SERVICE
using Microsoft.Azure.Mobile.Server.Tables;
#endif
namespace Abc.Base.Models
{
// The model class files are shared between the mobile and service projects.
public abstract class EntityData
#if SERVICE
: ITableData
#endif
{
#region ITableData Properties
public string Id { get; set; }
#if SERVICE
public DateTimeOffset? CreatedAt { get; set; } = DateTimeOffset.Now;
public DateTimeOffset? UpdatedAt { get; set; } = DateTimeOffset.Now;
public bool Deleted { get; set; }
public byte[] Version { get; set; }
#endif
#endregion
public DateTime? CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; }
}
}