Implementing simple cache in Windows Phone 8.1 Class Library - c#

I am trying to implement a simple caching mechanism in a windows phone 8.1 API that I am creating. I have chosen a Windows Phone Portable Class Library template in visual studio.
Refrence : http://channel9.msdn.com/Series/Windows-Phone-8-1-Development-for-Absolute-Beginners/Part-22-Storing-and-Retrieving-Serialized-Data
The cache class looks something like this,
[DataContract]
class cache
{
private const string JSONFILENAME = "data.json";
[DataMember]
Dictionary<Int32, item> cDictionary;
[DataMember]
int _maxSize;
public int MaxSize
{
get { return _maxSize; }
set { _maxSize = value; }
}
public cache(int maxSize){
cDictionary = new Dictionary<int, item>();
_maxSize = maxSize;
}
public void push(Int32 id, item obj)
{
if (!cDictionary.ContainsKey(id)) {
cDictionary.Add(id, obj);
}
}
internal static async Task<cache> Load()
{
cache obj = null;
try
{
var jsonSerializer = new DataContractJsonSerializer(typeof(cache));
using (var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(JSONFILENAME))
{
obj = (cache)jsonSerializer.ReadObject(myStream);
}
}
catch (FileNotFoundException)
{
obj = null;
}
return obj;
}
internal static async void Save(cache obj)
{
var serializer = new DataContractJsonSerializer(typeof(cache));
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(
JSONFILENAME,
CreationCollisionOption.ReplaceExisting))
{
serializer.WriteObject(stream, obj);
}
}}
The item class whose objects go into the dictionary looks like this,
[DataContract]
class item
{
[DataMember]
string _fName;
public string FName
{
get { return _fName; }
set { _fName = value; }
}
[DataMember]
string _lName;
public string LName
{
get { return _lName; }
set { _lName = value; }
}
[DataMember]
int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
public item(int id, string fName, string lName)
{
this.Id = id;
this.FName = fName;
this.LName = lName;
}
}
The idea is : The end user creates an instance of the api and calls a method doSomething(). The method first looks in the cache (not shown in the example) if found, returns the Item object back, or else, gets the item object from a web service(not shown) and then push it to cache.
public class api
{
cache tCache;
string apiKey;
public laas(string apiKey)
{
this.apiKey = apiKey;
this.tCache = new cache(100);
}
public async void Initialize(api obj)
{
//If cache exists
obj.tCache = await cache.Load();
if (obj.tCache == null)
{
obj.tCache = new cache(100);
}
}
public void doSomething(string id)
{
tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx"));
cache.Save(tCache);
}
}
I wanted to initialize/load the cache in the constructor of the api class, but since ApplicationData.Current.LocalFolder provide only async methods to read and write data from persistent storage, I created a separate static async class Initiialize() that would load the cache, since making an async constructor makes no sense.
Problem: the statement tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx")); in the doSomething() throws null reference exceptions. This could possibilly be happening because the tCache hasn't been loaded/initialized yet due to the async operation.
I had tried obj.tCache = await cache.Load().Result to wait for the loading to complete, but that hangs my application. (http://msdn.microsoft.com/en-us/magazine/jj991977.aspx)
Could you please point me in the right directions here? Is my diagnonis right? Is there a better way to do it? Any pointer is appreciated.
Thanks!

What is probably happening is that you're calling Initialize but not awaiting it, because it is async void.
What you need to do is change:
public async void Initialize(api obj)
To:
public async Task Initialize(api obj)
Then, you'll need to await Initialize(obj) which will ensure that caches completion before use.
Note that async void is ment only for top level event handlers and shouldn't be used otherwise.
Also, the reason Task.Result hangs your application is because it is causing a deadlock, which is related to the way async marshals your synchronization context between calls.

Related

Xamarin sqlite-net-pcl accessing values of database internal

I'm using Visual Studio 2017, new to SQLite and can't get my head behind how I get to access the values saved in the database and get it back to the elements of the class.
public class MyObject
{
[PrimaryKey, AutoIncrement]
public int IndexNumber
{get;set;}
[MaxLength(20)]
public int SomeID
{get;set;}
[MaxLength(70)]
public string SomeName
{get; set;}
[MaxLength(25)]
public string Telephone
{get; set;}
public DateTime someTime
{get; set;}
//...some more data
}
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB (string dbPath);
database.CreateTableAsync<MyObject>().Wait();
public Task<List<MyObject>> GetMyObjectAsync()
{
return database.Table<MyObject>().ToListAsync();
}
public Task<MyObject> GetSingleObjectAsync(int ind)
{
return database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public Task<int> SaveMyObjectAsync(MyObject object)
{
if (object.IndexNumber == 0)
{
return database.InsertAsync(object)
}
else
{
return database.UpdateAsync(object);
}
}
public Task<int> DeleteMyObjectAsync(MyObject object)
{
return database.DeleteAsync(object);
}
}
Inputting data through the .xaml pages works without any problems so far, selecting the object in ListView works as well.
The problem now is that I just can't seem to find a proper way to convert the returned Task back to an object to update some of those values with data only supplied through a HTTP response which itself does not always supply all the data for the datatable, e.g. only the ID and a code if it was successful in the first response.
It then needs other data from the object and again delivers values for different elements of the object which is why I'd like to know if there was some method to get a row of data back to a temporary object to update it in the database, remove it if needed (canceled through the HTTP response) or modify it.
Your problem is all about not using await keyword. Whenever you call asynchronous method with no await keyword you are doing it wrong :) I strongly recommend you to read James Montemagno blog post about it here.
Here is solution of your problems.
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
}
public async Task CreteMyDb()
{
await database.CreateTableAsync<MyObject>();
}
public async Task<List<MyObject>> GetMyObjectsAsync()
{
return await database.Table<MyObject>().ToListAsync();
}
public async Task<MyObject> GetSingleObjectAsync(int ind)
{
return await database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public async Task<int> SaveMyObjectAsync(MyObject myObject)
{
if (myObject.IndexNumber == 0)
{
return await database.InsertAsync(myObject);
}
else
{
return await database.UpdateAsync(myObject);
}
}
public async Task<int> DeleteMyObjectAsync(MyObject myObject)
{
return await database.DeleteAsync(myObject);
}
}
And example usage of methods.
await this.myDb.CreteMyDb();
await this.myDb.SaveMyObjectAsync(new MyObject()
{
SomeID = 1,
SomeName = "Adam",
someTime = DateTime.Now,
Telephone = "53535353"
});
var list = await this.myDb.GetMyObjectAsync();
Let me know if it helped!

Making asynchronous API synchronous

I am connecting to an API to get some data that is defined like this:
A client object ClientConnection, which allows one to send requests.
A IApi interface that needs to be passed to the ClientConnection to receive callbacks.
Schematically it looks like this:
// defined in the API dll
public class ClientConnection {
public ClientConnection(IApi api) { ... }
public void request(int reqid, string reqdetails) { ... }
}
interface IApi
{
void receiveData(int reqid, string ans);
}
Now, obviously this is a fairly standard asynchronous way of doing things: send requests through a global object, with a requestid, and receive answers tagged with that requestid.
I want to create a wrapper that is synchronous. What would be the most natural way of doing this? Is there a smart way of using async await, instead of using thread locking and stuff?
class MyWrapper : IApi
{
private ClientConnection _client;
private int _reqToken = 0;
public MyWrapper()
{
_client = new ClientConnection(this);
}
public string getData(string reqdetails)
{
_client.request(_reqToken++, reqdetails);
// what to do here?
}
public void receiveData(int reqid, string data) {
// what to do here?
}
}
Didn't test the code below, but it should give you the idea. Basically you can use ManualResetEvent to be signalled when you receive your result (and don't ever call this without proper timeout):
class MyWrapper : IApi {
private ClientConnection _client;
// here you store your requests
private Dictionary<int, PendingRequest> _pendingRequests = new Dictionary<int, PendingRequest>();
private int _reqToken = 0;
public MyWrapper() {
_client = new ClientConnection(this);
}
public string getData(string reqdetails, TimeSpan timout) {
// if this is multithreaded - lock over _pendingRequests when you add\remove requests there
// and when you increment your _reqToken, or use concurrent collection
using (var token = new PendingRequest()) {
var id = _reqToken;
// lock here
_pendingRequests.Add(id, token);
_client.request(id, reqdetails);
// and here use Interlocked.Increment
_reqToken++;
if (!token.Signal.WaitOne(timout)) {
// and here
_pendingRequests.Remove(id);
// timeout
throw new Exception("timout");
}
// if we are here - we have the result
return token.Result;
}
}
public void receiveData(int reqid, string data) {
// here you might need to lock too
if (_pendingRequests.ContainsKey(reqid)) {
var token = _pendingRequests[reqid];
_pendingRequests.Remove(reqid);
token.Complete(data);
}
}
private class PendingRequest : IDisposable {
public PendingRequest() {
Signal = new ManualResetEvent(false);
}
public ManualResetEvent Signal { get; private set; }
public string Result { get; private set; }
public void Complete(string result) {
this.Result = result;
Signal.Set();
}
public void Dispose() {
Signal.Dispose();
}
}
}

Serializing Model using NewtonSoft in WPF Application

I am trying to serialize my model each second and push it to a server. I have set up a periodic task which executes each second. I call SendNewMessage to execute the push.
The first method call to SendNewMessage() which is called from the constructor runs fine with no exceptions or issues.
When the async task tries to call the SendNewMessage I get an exception and my application shuts down. It is the NewtonSoft code:
String PushModelToServer = JsonConvert.SerializeObject(this, jss); Which fails
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in
'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x71041771, on thread 0x2788. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
public class Model : ModelBase
{
public Model ()
{
PeriodicTask.Run(() =>
{
SendNewMessage();
},
TimeSpan.FromSeconds(1));
SendNewMessage();
}
public void SendNewMessage()
{
// Send the message
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.Formatting = Newtonsoft.Json.Formatting.Indented;
String PushModelToServer = JsonConvert.SerializeObject(this, jss);
sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));
}
}
public class PeriodicTask
{
public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(period, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
action();
}
}
public static Task Run(Action action, TimeSpan period)
{
return Run(action, period, CancellationToken.None);
}
}
More Info As requested:
The call on line 10 in the constructor runs. The serialization works the first time. Since the data in the model is changing I am pushing this model every second to update server. It is the async call which fails. As time passes the data in the model will change.
You can use [IgnoreDataMember] to avoid serializing properties that should not be included.
The code below works in my application, and should hopefully help you arrive at a solution for your app.
I am hoping that the code you show above is a snippet of your real code because there are some potential issues with the 1 second timer, re-entrancy, etc. Instead of doing this timer in the Model constructor, consider moving it to another function/class and setting up the timer/calls from an additional call you setup later...again, just some suggestions on arriving at a good pattern. Do more research here...
Here is how I get my data, what you want in your PushModelToServer:
public class BackupData
{
public List<Vehicles> Vehicles { get; private set; }
public List<FuelStops> FuelStops { get; private set; }
public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
{
Vehicles = vehicles;
FuelStops = fuelStops;
}
public string ToJson(Formatting formatting = Formatting.None)
{
var json = JsonConvert.SerializeObject(this, formatting);
return json;
}
public static BackupData FromJson(string jsonBackupData)
{
var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
return data;
}
}
Here is a snippet of one of my classes:
[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (id != value) { id = value; NotifyPropertyChanged(); }
}
}
private string vehicleName;
public string VehicleName
{
get { return vehicleName; }
set
{
if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
}
}
public override string ToString()
{
return VehicleName;
}
[IgnoreDataMember]
public UpdateState UpdateState { get; set; }
....
And here is how I get the data so I can use it anywhere I want:
#if WINDOWS_PHONE_APP
private void OnExecuteBackup(SettingsPage obj)
{
#else
private async Task<bool> OnExecuteBackup(SettingsPage obj)
{
#endif
var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
...
await SaveBackupFile(file, backupData);
...
public class JournalModel
{
...
public BackupData GetBackupData()
{
var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
return data;
}
...
Good luck with your project.
Well there must be something the the class You're trying to serialize, that makes the serializer go crazy. Maybe instead of serializing 'this' You should try serializing an actual 'DataObject' - something that can be serialized, and doesn't contain references to Timers, tasks, ect.. ?

Getting property values from a static class using reflection

I have a class that is used for storing user data to a file. It works well, but can't really be placed into a PCL library easily. Outside of the PCL, it's all fine.
The class looks like this
public static class UserData
{
public static object GetPropertyValue(this object data, string propertyName)
{
return data.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(data, null);
}
public static object SetPropertyValue<T>(this object data, string propertyName, T value)
{
data.GetType().GetProperties().Single(pi => pi.Name == propertyName).SetValue(data, value);
return new object();
}
private static string pUserSettingsFile;
private static UserSettings userSetting;
public static bool AccountEnabled
{
get
{
return UserSettings.account_enabled;
}
set
{
UserSettings settings = UserSettings;
settings.account_enabled = value;
UserSettings = settings;
}
}
public static UserSettings UserSettings
{
get
{
if (userSetting == null)
{
if (File.Exists(UserSettingsFile))
{
userSetting = Serializer.XmlDeserializeObject<UserSettings>(UserSettingsFile);
}
else
{
userSetting = new UserSettings();
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
return userSetting;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value is null!");
}
userSetting = value;
if (File.Exists(UserSettingsFile))
{
File.Delete(UserSettingsFile);
}
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
public static string UserSettingsFile
{
get
{
if (string.IsNullOrEmpty(pUserSettingsFile))
{
pUserSettingsFile = Path.Combine(GroupShootDroid.Singleton.ContentDirectory, "UserSettings.xml");
}
return pUserSettingsFile;
}
}
#endregion
}
public class UserSettings
{
public bool account_enabled { get; set; }
public string address { get; set; }
public string country { get; set; }
}
It's not rocket science, but does what I need it to do.
What I'm trying to do is use the Get/SetPropertyValue methods to return or set any of the properties within the class.
Currently, to access the Get/SetPropertyValue methods I'm using this
public string GetStringValue(string valToGet)
{
string rv = (string)UserData.GetPropertyValue(valToGet);
return rv;
}
public void SetStringValue(string name, string val)
{
UserData.SetPropertyValue(name, val);
}
On compiling though, the GetPropertyValue method is giving an error that No overload for method GetPropertyValue takes 1 argument with the SetPropertyValue complaining that there isn't an overload that takes 2
I'm not sure that the code I'm using will do what I need it to do (from what I've read on here it should be), but I'm more perplexed as to why the errors are showing.
Is there a better way to do what I'm trying to do? The application is a Xam.Forms app, so the PCL accesses the class through an interface using injection.
You are defining extension method, you need an instance of the class to call them:
var o = new Object();
string rv = (string)o.GetPropertyValue(valToGet);
// or, but no sure
string rv = (string)UserData.GetPropertyValue(o, valToGet);
or more probably in your case:
public string GetStringValue(string valToGet)
{
string rv = (string)this.GetPropertyValue(this, valToGet);
//or
//string rv = (string)UserData.GetPropertyValue(this, valToGet);
return rv;
}
I think you're getting confused between the UserData class and the object class. Your extension methods extend object.

Sharing session data between frames and support load/restore state

Let's say that I have a list in my main frame in a windows store app with session data. When I click an item a new frame is open where I could edit the data.
How do I properly share session data between the frames, and how do I save and restore session data so that the references between the objects are intact?
I know that I could send an object as parameter when a new frame is created. I also know how to save/restore session data. I just don't how to solve this :).
You can use NavigationService to send data to new frames as mentioned in the option below. it is more like sending keyvalur pairs as uri parameters:
NavigationService.Navigate(new Uri("/Page1.xaml?parameter1=p1&parameter2=p2", UriKind.Relative));
To get value:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string parameterValue = NavigationContext.QueryString["parameter"];
}
http://www.geekchamp.com/tips/how-to-pass-data-between-pages-in-windows-phone-alternatives
Also if you want to share complex objects you might need to create nested viewmodels but if you don't have luxury to nest viewmodels due to nature of views then you might need to create a static app cache to use a medium to persist/share object among frames.
Storing global references to objects isn't all that tricky. You can just have a static holder that does or doesn't have the responsibility to persist them. Oh, something like this:
public interface IViewModel { }
public class ViewModelOne : IViewModel { }
public class ViewModelTwo : IViewModel { }
public class ViewModelThree : IViewModel { }
public static class GlobalObjects
{
private static ViewModelOne viewModelOne = null;
public static ViewModelOne ViewModelOne
{
get { return Get<ViewModelOne>(ref viewModelOne); }
set { Set(ref viewModelOne, value); }
}
private static T Get<T>(ref T storage) where T : IViewModel, new()
{
if (storage != null)
return storage;
try
{
var json = Load(typeof(T).ToString());
return storage = Deserialize<T>(json);
}
catch (Exception)
{
return new T();
}
}
private static void Set<T>(ref T storage, T value) where T : IViewModel
{
if (storage?.Equals(value))
return;
try
{
var json = Serialize(value);
Save(json, typeof(T).ToString());
}
catch (Exception)
{
Save(string.Empty, typeof(T).ToString());
}
}
private static void Save(string value, string key)
{
throw new NotImplementedException();
}
private static string Serialize(object obj)
{
throw new NotImplementedException();
}
private static string Load(string key)
{
throw new NotImplementedException();
}
private static T Deserialize<T>(string obj)
{
throw new NotImplementedException();
}
}
Best of luck!
// Jerry
After some inspiration from Shoaib Shaikh I decided to do a global repository. Please review this cause I barely know what I’m doing :-).
I have three classes. All classes use DataContract so it’s easy to serialize. First PersonViewModel which is pretty straight forward:
[DataContract()]
public class PersonViewModel : BaseViewModel
{
public PersonViewModel(string name)
{
Name = name;
}
#region Name property
[DataMember()]
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
SetPropertyValue(ref _Name, value, () => Name);
}
}
#endregion
}
Second is the PersonListViewModel . Each PersonViewModel is stored in a global hash table with a string id. This class taking care of the ID:s. By calling RefreshPersonCollection the person list is rebuild from the global objects. Quite clumsy, it’s better to get the persons on request but I’m too tired to solve that right now :-).
[DataContract()]
public class PersonListViewModel : BaseViewModel
{
[DataMember()]
private List<string> PersonIds = new List<string>();
public PersonListViewModel()
{
Persons = new ObservableCollection<PersonViewModel>();
CreateDefaultData();
}
public void CreateDefaultData()
{
for(int i=0; i<3; i++)
{
string personid = Guid.NewGuid().ToString();
string personname = "Person " + personid;
PersonViewModel person = new PersonViewModel(personname);
PersonIds.Add(personid);
Persons.Add(person);
SharedObjects.Instance.Objects[personid] = person;
}
}
public void RefreshPersonCollection()
{
Persons = new ObservableCollection<PersonViewModel>();
foreach (string personid in PersonIds)
{
Persons.Add((PersonViewModel)SharedObjects.Instance.Objects[personid]);
}
}
public ObservableCollection<PersonViewModel> Persons{ get; set; }
}
Third class is my global repository. Also quite straight forward I think. All PersonViewModels and all PersonListViewModel is stored in this repository.
[DataContract()]
public class SharedObjects
{
public static SharedObjects Instance;
public SharedObjects()
{
Objects = new Dictionary<string, object>();
}
public void Init()
{
Objects["mainviewmodel"] = new PersonListViewModel();
}
[DataMember()]
private Dictionary<string, Object> _Objects;
public Dictionary<string, Object> Objects
{
get { return _Objects; }
set { _Objects = value; }
}
}
In my Windows store application I have a SuspensionManager that I have modified it slightly to serialize and deserialize my global repository.
First change was to add my new types to known types to be serialized. I don’t like this, would prefer that the classes could do this themselves somehow (which is possible as far as I understand it).
static SuspensionManager()
{
_knownTypes.Add(typeof(SharedObjects));
_knownTypes.Add(typeof(PersonListViewModel));
_knownTypes.Add(typeof(PersonViewModel));
}
Second change is in SaveAsync to make sure the global data is saved. Just one line was added:
//I added this:
_sessionState["globalobjects"] = SharedObjects.Instance;
// Serialize the session state synchronously to avoid asynchronous access to shared
// state
MemoryStream sessionData = new MemoryStream();
DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
serializer.WriteObject(sessionData, _sessionState);
Third change is in RestoreAsync.
// Get the input stream for the SessionState file
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(sessionStateFilename);
using (IInputStream inStream = await file.OpenSequentialReadAsync())
{
// Deserialize the Session State
DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
_sessionState = (Dictionary<string, object>)serializer.ReadObject(inStream.AsStreamForRead());
}
//I added this:
if (_sessionState.ContainsKey("globalobjects"))
SharedObjects.Instance = (SharedObjects) _sessionState["globalobjects"];
This feels manageable but any suggestions for improvements are appreciated :-). Will this work in Windows Phone as well (except for SuspensionManager, but I guess it's something similar on that platform)?

Categories