windows 8 app roaming storage with custom class - c#

I am learning programming in windows 8 with c#. I have worked through many tutorials (such as http://msdn.microsoft.com/en-us/library/windows/apps/hh986968.aspx) in the process and I am attempting to create a simple app showing data storage. All of the examples I have been able to find store only simple strings in roaming storage. Is there a way to store more complex data there?
example: a List of a basic class Person with a name and age. I attempted to do it as:
Saving the data:
roamingSettings.Values["peopleList"] = people;
Loading the Data:
people = (List)roamingSettings.Values["peopleList"];
WinRT information: Error trying to serialize the value to be written to the application data store.
when saving the data I get the error "Data of this type is not supported"
So, maybe all you can save is string values -- but I have not seen that specified anywhere either.

Yes, you can save your values to raoming data as a collection. The solution for your problem is
ApplicationDataCompositeValue class
See http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdatacompositevalue.aspx for more information
As you mentioned, You are developing in C# , following is the code for your problem
I imagined, you have a Person class with two members
class person
{
int PersonID;
string PersonName
}
Now, to read and write values for this class, here is the code
First in the constructor of your Window class, under the InitializeComponent();, create an object of roaming settings
Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
To Write to a composition, use the following code
void write (Person Peopleobj)
{
Windows.Storage.ApplicationDataCompositeValue composite = new Windows.Storage.ApplicationDataCompositeValue();
composite["PersonID"] = Peopleobj.PersonID;
composite["PersonName"] = Peopleobj.PersonName;
roamingSettings.Values["classperson"] = composite;
}
To Read a Person object, use the following code
void DisplayOutput()
{
ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)roamingSettings.Values["classperson"];
if (composite == null)
{
// "Composite Setting: <empty>";
}
else
{
Peopleobj.PersonID = composite["PersonID"] ;
Peopleobj.PersonName = composite["PersonName"];
}
}

Related

Firebase data - error converting value

I have posted question regarding firebase two days ago:
Android Firebase - add authenticated user into database
I got help that I needed and that solved first problem. But now I have a new problem. I was googling for quite some time, there are some posts about this issue but nothing solved my problem. I din't want to spam the previous question so I posted a new one.
When I try reading inserted data from the firebase database I get this error:
Newtonsoft.Json.JsonSerializationException: Error converting value
"test#user.com" to type 'carServiceApp.My_Classes.Account'. Path
'email', line 1, position 24.
Here is the code:
private async Task LoadData()
{
FirebaseUser users = FirebaseAuth.GetInstance(loginActivity.app).CurrentUser;
id = users.Uid;
var firebase = new FirebaseClient(loginActivity.FirebaseURL);
var items = await firebase.Child("users").Child(id).OnceAsync<Account>();
foreach (var item in items)
{
Account user = new Account();
user.uid = item.Object.uid;
user.name = item.Object.name;
user.lastName = item.Object.lastName;
user.phone = item.Object.phone;
user.email = item.Object.email;
userInput_ime.Text = user.name;
userInput_prezime.Text = user.lastName;
userInput_broj.Text = user.phone;
userInput_email.Text = user.email;
}
}
This is firebase data:
-users
-jwAP2dYNzJeiF3QlmEIEQoruUkO2
email: "test#user.com"
lastName: "user"
name: "test"
phone: "12421"
uid: "jwAP2dYNzJeiF3QlmEIEQoruUkO2"
Interesting thing is that when I try reading data with this:
var items = await firebase.Child("users").OnceAsync<Account>();
This works fine (I get last inserted user) . But when I add 'uid' node, then I get error. I was trying to solve this for quite some time but I just can't figure it out. I guess that there is no problem with the account class because it works in the case without uid node but doesn't work when another child() method is added.
Other information (Account class code and the way of storing that data into the database) you can see in the link at the top.
Note: I tried adding constructor in Account class but that doesn't help.
Ok, so I didn't exactly find a solution for this problem nor do I really understand why was this happening but I have found a workaround. I believe it's not ideal solution and that it does not fix existing problem. Or maybe it was problem with me not understanding firebase logic but here is what I came up with.
So, considering that it was all working fine if I didn't specify that uid node it was obvious there was some problem with class and data in firebase, matching problem I guess. Anyway, I decided to have that last uid node so I can have specific user selected and also to have the same data in firebase as it was in case where it was all working. So, this is how I have inserted data into firebase:
var item = firebase.Child("users").Child(id).PostAsync<Account>(user);
This created users node and child node. And PostAsync method created one more node with random key.
So when I tried reading with this:
var data = await firebase.Child("users").Child(id).OnceAsync<Account>();
It worked without problem. Now firebase data looks like this:
users
JPKdQbwcXbhBatZ2ihBNLRauhV83
-LCXyLpvdfQ448KOPKUp
email: "spider#man.com"
lastName: "man"
name: "spider"
phone: "14412"
uid: "JPKdQbwcXbhBatZ2ihBNLRauhV83"
There is a bit of redundancy, I basically have two ID's, but I don't understand how to create my class so I can get that data any other way so I made it this way. It works fine.
If anyone has better solution, I will gladly change it. Cheers
This was suppose to be a comment, but this is just suppose to be an addition for anyone that needs help with this issue.
I know that this answer has been out there for a while but this still seems to be a running structural quirk with Firebase and the usage of their rules. I ran into this issue with a complex structure that looked kind of like this
-Orders
-9876trfghji (User ID)
-0
BusnID: "ty890oihg"
Name: "Some Name"
AddOns: Object
ItemData: Object(containing other objects)
UserID: "9876trfghji"
Note: In this case as well as the case with cordas, you will see that both of the final objects has a UserID or uid.
I also was running into the issue of class de-serialization of the object without having the actual User ID in the objects data when it was being sent back to the device.
The reason that you have a “redundant” usage of the user id is for a security measure with the Firebase rules. The first UserID with the structure above you are able to control the access to the information based off of the users id without having to have an extra validation clause in the rules. Currently as of this post the the rule below would protect the data based on the User ID.
“Orders” : {
"$uid":{
".read":"auth != null",
".write":"auth.uid == $uid"
}
}
this allows the user with only the authorized user id to write content but anyone that has valid credentials can view the data.
The second User ID has to be placed in the object because without it you would not be able to do a standard cast to the object because your object would not have all of the data it would need to create the object. Regardless of if you are using a package like GoogleGson or Newtonsoft.Json the object still isn't full.
There is how ever a work around for this problem besides re-entering the User ID into the object. With the object that I have above I decided to just re-enter the User ID in my personal code to save the time and hassle of manual creation.
Using the Firebase.Database NuGet package you can manually create the object. Here is an example of the object in cordas problem
public static void GetUser_Firebase(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"/users/{user.UserID}");
//"Using for getting firebase information", $"/users/{user.UserID}"
reference.AddListenerForSingleValueEvent(new UserInfo_DataValue());
}
class UserInfo_DataValue : Java.Lang.Object, IValueEventListener
{
private string ID;
public UserInfo_DataValue(string uid)
{
this.ID = uid;
}
public void OnCancelled(DatabaseError error)
{
//"Failed To Get User Information For User "
}
public void OnDataChange(DataSnapshot snapshot)
{
Dictionary<string, string> Map = new Dictionary<string, string>();
var items = snapshot.Children?.ToEnumerable<DataSnapshot>(); // using Linq
foreach(DataSnapshot item in items)
{
try
{
Map.Add(item.Key, item.Value.ToString()); // item.value is a Java.Lang.Object
}
catch(Exception ex)
{
//"EXCEPTION WITH DICTIONARY MAP"
}
}
User toReturn = new User();
toReturn.UserID this.ID;
foreach (var item in Map)
{
switch (item.Key)
{
case "email":
toReturn.email = item.Value;
break;
case "lastName":
toReturn.lastName = item.Value;
break;
case "name":
toReturn.name = item.Value;
break;
case "phone":
toReturn.phone = item.Value;
break;
}
}
}
}
Update
There is something that I would like to mention that I left out when I was writing this and that is the usage of Firebase.Database NuGet package with the Gson NuGet package and the Newtonsoft.Json Library
If you decide to use the FIrebase.Database library just know that you will be working very close with the Java.Lang and the Java.Util libraries. Objects like Java.Lang.Object can be very difficult and time consuming to write the code needed to de-serialize the data, but don't fear Gson is here!
The Gson package if you allow it can take a large load of work off of your hands for class de-serialization if you allow it. Gson is a library that will allow you to do Java.Lang.Obj to json string de-serialization. I know it seems weird, hand it an object get back a string sounds counter intuitive I know but just bear with me.
Here is an example of how to us the Gson Library with the object in cordas problem.
public static void Get_User(User user, FirebaseApp app)
{
FirebaseDatabase database = FirebaseDatabase.GetInstance(app);
DatabaseReference reference = database.GetReference($"Users/{user.UserID}");
reference.AddListenerForSingleValueEvent(new User_DataValue(user, app));
//$"Trying to make call for user orders Users/{user.UserID}");
}
class User_DataValue : Java.Lang.Object, IValueEventListener
{
private User User;
private FirebaseApp app;
public UserOrderID_Init_DataValue(User user, FirebaseApp app)
{
this.User = user;
this.app = app;
}
public void OnCancelled(DatabaseError error)
{
//$"Failed To Get User Orders {error.Message}");
}
public void OnDataChange(DataSnapshot snapshot)
{
//"Data received for user orders");
var gson = new GsonBuilder().SetPrettyPrinting().Create();
var json = gson.ToJson(snapshot.Value); // Gson extention method obj -> string
Formatted_Output("Data received for user order json ", json);
User user = JsonConvert.DeserializeObject<User>(json); //Newtonsoft.Json extention method string -> object
//now the user is a fully populated object with very little work
}
For anyone that might run into this in the future I hope that this helps

Use variable value to check if particular instance exists, if not - create it

I have a list of images like this:
public List<Image> imageList = new List<Image>();
I also have a picture class in order to collect and manipulate data about the images in the list:
public Class Pic {
// properties and stuff
}
And then I have a function that takes an integer as an argument. That integer corresponds to an image in the image list. What I want to do in the function is to check if an instance of the Pic class has been created for that particular image. If not, I want to create it, using the value of the variable passed into the function. The following code obviously doesn't work, but it shows what I want:
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(pic + picNumber.toString() == null) {
// Create an instance
Pic pic + picNumber.toString() = new Pic();
}
}
Suggestions on how to accomplish this?
It seems like you're trying to create individual variables pic1, pic2, etc. you'd be better off using a dictionary:
Dictionary<int, Pic> pics = new Dictionary<int, Pic>();
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(!pics.ContainsKey(picNumber)) {
// Create an instance
pics[picNumber] = new Pic();
}
}
You need to create a "registry" of known Pics. DIctionary<int,Pic> would be good collection to hold this registry. You need to store the registry itself somewhere - perhaps in the "factory" object that registers your pictures.
class PicFactory {
private readonly IDictionary<int,Pic> knownPics = new Dictionary<int,Pic>();
public Pic GetOrCreate(int id) {
Pic res;
if (knownPics.TryGetValue(id, out res)) {
return res;
}
res = new Pic(id.ToString()); // This assumes that Pic(string) exists
knownPics.Add(id, res);
return res;
}
}
This way of implementing a registry may be too primitive for your purposes - for example, if you need your registry to be concurrent, you would need to set up some sort if a locking scheme to protect the knownPics dictionary. The class that accesses pictures would need to create an instance of PicFactory, so that it could access pictures through the GetOrCreate(id) call.
If you are using .net 4.0 or more you can use Lazy type which:
Provides support for lazy initialization.
Which means that the object will be constructed not in the moment of declaration, but when first accessed.
So you can basically declare them like
List<Lazy<Pic>> ....
See Lazy<T> and the Lazy Loading Pattern in general - this is actually a common optimization technique as it defers what can add up to a lot at startup to microdelays during runtime.
Be wary about making sure the microdelays are worth it, and I advise leaving methods about which can force loading.
If you're grabbing from a list, preface with a .Any or .Contains check, and since you're looking up by name like that, consider using a Dictionary instead

IsolatedStorage and navigation

I can't sort this weird issue out and I have tried anything and everything I can think of.
I got 5 pages, everyone of them passing variables with navigation this way:
Pass:
NavigationSerice.Navigate(new Uri("/myPage.xaml?key=" + myVariable, UriKind.Relative));
Retrieve:
If (NavigationContext.QueryString.ContainsKey(myKey))
{
String retrievedVariable = NavigationContext.QueryString["myKey"].toString();
}
I open a list on many pages and one of the pages automatically deletes an item from the list actualProject (actualProject is a variable for a string list). Then, when I go so far back that I reach a specific page - the app throws an exception. Why? I have no idea.
The code that deletes the item:
// Remove the active subject from the availible subjects
unlinkedSubjects.Remove(actualSubject);
unlinkedsubjectsListBox.ItemsSource = null;
unlinkedsubjectsListBox.ItemsSource = unlinkedSubjects;
Then the page that throws the exception's OnNavigatedTo event:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (NavigationContext.QueryString.ContainsKey("key"))
{
actualProject = NavigationContext.QueryString["key"];
try
{
//Read subjectList from IsolatedStorage
subjectList = readSetting(actualProject) != null ? (List<String>)readSetting(actualProject) : new List<String>();
//Put the subjectList into the subjectListBox
subjectListBox.ItemsSource = subjectList;
//Set the subjectsPageTitle to the "actualProject" value, to display the name of the current open project at the top of the screen
subjectsPageTitle.Text = actualProject;
}
catch (Exception)
{
if (language.Equals("en."))
{
// Language is set to english
MessageBox.Show("Couldn't open the project, please try again or please report the error to Accelerated Code - details on the about page");
}
else if (language.Equals("no."))
{
// Language is set to norwegian
MessageBox.Show("Kunne ikke åpne prosjektet, vennligst prøv igjen eller rapporter problemet til Accelerated Code - du finner detaljer på om-siden");
}
}
}
}
Exception:
_exception {System.ArgumentException: Value does not fall within the expected range.} System.Exception {System.ArgumentException}
My theory:
The app kind of loads the currently opened and modified List. Is that possible? No idea.
So there are a number of ways to pass data between pages.
The way you have chosen is the least suggested.
You can use the PhoneApplicationService.Current dictionary but this is messy also if you have a ton of variables, doesn't persist after app shut down and could be simplified.
I wrote a free DLL that kept this exact scenario in mind called EZ_iso.
You can find it here
Basically what you would do to use it is this.
[DataContractAttribute]
public class YourPageVars{
[DataMember]
public Boolean Value1 = false;
[DataMember]
public String Value2 = "And so on";
[DataMember]
public List<String> MultipleValues;
}
Once you have your class setup you can pass it easily between pages
YourPageVars vars = new YourPageVars { /*Set all your values*/ };
//Now we save it
EZ_iso.IsolatedStorageAccess.SaveFile("PageVars",vars);
That's it! Now you can navigate and retrieve the file.
YourPageVars vars = (YourPageVars)EZ_iso.IsolatedStorageAccess.GetFile("PageVars",typeof(YorPageVars));
This is nice because you can use it for more than navigation. You can use it for anything that would require Isolated storage. This data is serialized to the device now so even if the app shuts down it will remain. You can of course always delete the file if you choose as well.
Please make sure to refer to the documentation for any exceptions you have. If you still need help feel free to hit me up on twitter #Anth0nyRussell or amr#AnthonyRussell.info

Manage/Update Records in ASP.NET With Redis using ServiceStack

I'm coming from a SQL Server background, and experimenting with Redis in .NET using ServiceStack. I don't mean for Redis to be a full replacement for SQL Server, but I just wanted to get a basic idea of how to use it so I could see where we might make good use of it.
I'm struggling with what I think is a pretty basic issue. We have a list of items that are maintained in a couple of different data stores. For the sake of simplicity, assume the definition of the item is basic: an integer id and a string name. I'm trying to do the following:
Store an item
Retrieve an item if we only know its id
Overwrite an existing item if we only know its id
Show all the items for that specific type
And here's some of the code I've put together:
public class DocumentRepositoryRedis
{
private static string DOCUMENT_ID_KEY_BASE = "document::id::";
public IQueryable<Document> GetAllDocuments()
{
IEnumerable<Document> documentsFromRedis;
using (var documents = new RedisClient("localhost").As<Document>())
{
documentsFromRedis = documents.GetAll();
}
return documentsFromRedis.AsQueryable();
}
public Document GetDocument(int id)
{
Document document = null;
using (var redisDocuments = new RedisClient("localhost").As<Document>())
{
var documentKey = GetKeyByID(document.ID);
if (documentKey != null)
document = redisDocuments.GetValue(documentKey);
}
return document;
}
public void SaveDocument(Document document)
{
using (var redisDocuments = new RedisClient("localhost").As<Document>())
{
var documentKey = GetKeyByID(document.ID);
redisDocuments.SetEntry(documentKey, document);
}
}
private string GetKeyByID(int id)
{
return DOCUMENT_ID_KEY_BASE + id.ToString();
}
}
It all seems to work - except for GetAllDocuments. That's returning 0 documents, regardless of how many documents I have stored. What am I doing wrong?
The typed Redis client also gives you access to the non-typed methods - since Redis ultimately doesn't know or care about your object types. So when you use the client.SetEntry() method, it bypasses some of the typed client's features and just stores the object by a key. You'll want to use the client.Store method since it goes ahead and creates a SET in Redis with all the object IDs related to your type. This SET is important because it's what the GetAll method relies on to serve back all the objects to you. The client.Store method does infer the ID automatically so you'll want to play around with it.
You'd change your GetDocument(int id) and SaveDocument(Document document) methods to use the client.GetById(string id) method, and you'd use client.Store(T value) method. You won't need your GetKeyByID() method anymore. I believe your Document object will need an "Id" property for the typed client to infer your object ID.

c# class in a session state?

My senior project is building a reservation system in ASP.NET/C#. Part of my senior project is to have c# classes (and basically use everything ive learned in the past few years). One thing Im trying to do is after I instantiate a new "user" class I need it to travel between the pages. I know session states holds variables, so I figured a session state would work where I can simply type "Session["blah"]." and have access to its members. But I dont see that happening. I realize session states are HTTP context, so i doubted it would work anyway. But is there any other way in which I can accomplish what I need without instantiating a new user class every time? I know its a webpage...but im also trying to make it as much as a functional online program as I can.
Just for coder's sake, heres the code snippet im working with:
cDatabaseManager cDM = new cDatabaseManager();
string forDBPass = Encryptdata(pass_txt.Text.ToString());
string fullName = fname_txt.Text.ToString() + " " + lname_txt.Text.ToString();
cDM.regStudent(email_txt.Text.ToString(), forDBPass, fullName, num_txt.Text.ToString(), carrier_ddl.SelectedValue.ToString(), this);
//ADD - getting a cStudent
cUser studentUser = new cStudent(fullName, forDBPass, email_txt.Text.ToString());
//ADD - session states
Session["cStudent"] = studentUser;
//Session["cStudent"]. //session state will not work with what I am doing
//ADD - transfer to campus diagram
Thanks in advance!!
EDIT:
I want to thank all of you who posted and commented! Ive learned alot from this short discussion. All your answers helped me understand!
From your comment:
The issue is when I type "Session["cStudent"]." I don't have access to my functions. Example: Session["cStudent"].getName() does not give my functionality.
This is because the [] indexer for Session sets/returns objects. The compiler does not know that you stored a cUser object and so you can't access the properties directly without a cast:
string name = ((cUser)Session["cStudent"]).getName();
There are two things that could go wrong here:
If Session["cStudent"] is null you will get a NullReferenceException
If Session["cStudent"] is not really a cUser you will get an InvalidCastException
You should check these conditions and react appropriately if one of them is true.
Also, as others have pointed out, the cUser class needs to be marked as Serializable in order to be stored in Session state.
Session stores item as objects. As long as your class inherits from Object (which it does) you can store it there. Quick caveat, it stores that object using Serialization, so your class must be serializable.
Add a property to your class like so:
public cStudent CurrentStudent
{
get {
if(Session["CurrentUser"] == null)
return null;
return (cStudent)Session["CurrentUser"];
}
set {
Session["CurrentUser"] = value;
}
}
When retrieving an object value from session state cast it to appropriate type.
[Serializable]
public class student
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In Page1:
student s1 = new student();
s1.FirstName ="James";
s1.LastName = "Bond";
Session["blah"] = s1;
And when you want to access Session["blah"] in page 2
student s2 = (Session["blah"] !=null ? (student)Session["blah"] : null);
Now you can access properties of s2 as s2.FirstName, s2.LastName

Categories

Resources