So, I'm developing a contact management system and I'm trying to add a contact. Instead of jumping between ViewModels(the contact and main contact page are separate), I've decided to take in data from the view, create a contact, add it to a list then serialize that list. Then, when I get back to the main page, I deserialize that list.
This works fine(no optimization, this is just a simple college project) as the data is added to the JSON file. My problem is- when I navigate back to the main page- the list doesn't update due to an UnauthorisedAccessException on my stream. The deserialization method is:
private async void buildMyListWithJsonAsync(){
ObservableCollection<Contact> list = new ObservableCollection<Contact>();
try
{
string JSONFILENAME = "contacts.json";
string content = " ";
StorageFile File = await ApplicationData.Current.LocalFolder.GetFileAsync(JSONFILENAME);
using (IRandomAccessStream testStream = await File.OpenAsync(FileAccessMode.Read)){
using (DataReader dreader = new DataReader(testStream)){
uint length = (uint)testStream.Size;
await dreader.LoadAsync(length);
content = dreader.ReadString(length);
list = JsonConvert.DeserializeObject<ObservableCollection<Contact>>(content);
}
}
contactlist = new ObservableCollection<Contact>();
foreach (Contact c in list)
contactlist.Add(c);
}
catch (Exception e)
{ e.ToString(); }
}
Any help or aid would be appreciated.
I'd hazard an educated guess that the issue is around threading and your ObservableCollection. ObservableCollections aren't threadsafe and involve raising events on the UI thread they're created on typically & StorageFile API is all async thread based.
Have a shot at pulling the string back from the async thread and doing the Serialization and Deserialization on the main UI thread instead and that may well resolve it.
Related
I am attempting to create the backend of a Twitch Extension that will search for all other users streaming the same game. The only way to get the Category with which to compare games is if the channel in question is live. This is fine, as the extension should will only be working whenever the stream goes live.
My issue is that I do not know how I can determine whether or not the user of the extension has gone online.
public static async Task<string> GetStreamAsync()
{
string product = "";
List<Stream> finalProduct = new List<Stream>();
var response = await _httpClient.GetAsync("https://api.twitch.tv/helix/streams?user_login=Ninja");
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsStringAsync();
var streamToRelate = JsonConvert.DeserializeObject<RootStream>(product);
finalProduct = await GetAllRelatedChannels(streamToRelate.Data.FirstOrDefault());
}
return product;
}
As you can see, I've hard coded a stream that I knew was online at the time (Ninja). This data was returned perfectly fine, but the next step is to pass a string into this function with which to search. How could I go about getting the "User" of the extension at runtime? If I am completely off-base, and am missing certain concepts, please let me know as well and I will do further research if necessary.
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
I'm building a Windows Phone 8 App using a recipe API, the API returns data in XML and up to this point I've not had many problems with parsing API responses, however, after making a search for a recipe, a user should then be able to tap on a particular search result and see more information on that recipe, this is a Pivot page with three headers:
Details (Which contains the recipe name, image and description)
Ingredients (Obviously listing the ingredients and quantities)
Instructions (Contains the prep and cooking instructions)
I have no problem getting the elements for the Details and Instructions pages as there is only one of each of these elements in the xml returned by the API, however with Ingredients, each ingredient has its own section in the xml, so I thought a foreach loop in the code would be able to get all the details into a list, however, when running the app and navigating to this page, the app seems to load multiples of ALL the information, including items on the Details and Instructions pages.
So, there are now lots of the same image, title and decryption displayed on the details page, lots of the same instructions on the instructions page and lots of the same ingredient on the ingredients page. I'm not quite sure how to go about solving this as everything I try doesn't work.
Removing the foreach loop from the code below stops the app loading loads of the same information, but obviously without any ingredients, please see the code below, I'm unable to post an API link because there is a limit to how many requests I can make per hour, and inserting it here formats it in an unclear way, does anyone know any steps to try and fix this issue?
The code:
void bigOvenRecipe_RecipeDetailsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var xdoc = XDocument.Parse(e.Result);
Details content = new Details();
List<Details> contentList = new List<Details>();
try
{
content.RecipeImage = xdoc.Root.Element("ImageURL").Value;
content.Title = xdoc.Root.Element("Title").Value;
content.Description = xdoc.Root.Element("Description").Value;
content.Instructions = xdoc.Root.Element("Instructions").Value;
contentList.Add(content);
foreach (XElement item in xdoc.Elements("Recipe").Elements("Ingredients").Elements("Ingredient"))
{
content.IngredientName = item.Element("Name").Value;
content.IngredientQuantity = item.Element("Quantity").Value;
content.IngredientUnit = item.Element("Unit").Value;
contentList.Add(content);
}
}
catch (Exception error)
{
MessageBox.Show("An error was encountered while performing this request: " + error.Message);
}
detailsList.ItemsSource = contentList.ToList();
ingredientsList.ItemsSource = contentList.ToList();
instructionsList.ItemsSource = contentList.ToList();
}
Thank you in advance!
One glaring issue that I see is that you keep adding the same content object to contentList.
I'm guessing that Details is a reference type, and content is only a reference to that one Details object.
your entire contentList is just a bunch of references to the same object.
Try instantiating a new object for each ingredient.
foreach (XElement item in xdoc.Elements("Recipe").Elements("Ingredients").Elements("Ingredient"))
{
Details content = new Details();
// initialize other values
content.IngredientName = item.Element("Name").Value;
content.IngredientQuantity = item.Element("Quantity").Value;
content.IngredientUnit = item.Element("Unit").Value;
contentList.Add(content);
}
I want to get all contacts stored in phone and update them as per requirement.
http://www.silverlightshow.net/items/Windows-Phone-8-Contacts-Integration.aspx
This link shows to get contacts but I'm not getting all contacts. I'm only getting contacts that have been created using my app.
Is there any way I can get all contacts and change mobile numbers.
Thanks
From the link you provided (emphasis added):
With Windows Phone 8, Microsoft introduces a new concept of "custom
contact stores" [2]. In addition to the read-only access to the user's
contact list and the above demonstrated way to use a separate task for
creating new entries (both of which available in 7.x) we now are able
to write our own data to the people hub silently and without user
consent. However apps still cannot manipulate existing contacts that
originate from somewhere else. In this sense, the data that belongs to
an app is somewhat isolated from the rest.
This is by design, you can't edit contacts you didn't create.
try something like this
void GetContact()
{
cons = new Contacts();
//Identify the method that runs after the asynchronous search completes.
cons.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(ContactsSearchCompleted);
//Start the asynchronous search.
cons.SearchAsync(String.Empty, FilterKind.None, "Contacts Test #1");
}
private void ContactsSearchCompleted(object sender, ContactsSearchEventArgs e)
{
cons.SearchCompleted -= ContactsSearchCompleted;
//e.Results should be the list of contact, since there's no filter applyed in the search you shoul have all contact here
}
not this is a copy paste of an old not tested code of mine so you might have to change something
You cant' - stupid crappy MS don't even support contact import from vcard file. ALL MS want that you put every your data to their servers so they own it.
At first you should at Contact Capability
for wp8 add from WMAppManifest.xml
for wp8.1 add from Package.appxmanifest
Now define a class PhoneContact to store the data
public class PhoneContact {
public string Name { get; set; }
public string Number { get; set; }
public string Email { get; set; }
}
Create a ObservableCollection and Call the following action from constructor to read the contact list. N.B use the following namespace also
using Microsoft.Phone.UserData;
using System.Collections.ObjectModel;
ObservableCollection<PhoneContact> phoneContact;
public MainPage() {
InitializeComponent();
phoneContact = new ObservableCollection<PhoneContact>();
ReadPhoneContact();
}
void ReadPhoneContact(){
Contacts cnt = new Contacts();
cnt.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(Contacts_SearchCompleted);
cnt.SearchAsync(String.Empty, FilterKind.None, "Contacts Test #1");
}
After reading all contact fire the following event. you can read multiple contact number, email etc.
void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
{
foreach (var item in e.Results) {
var contact = new PhoneContact();
contact.Name = item.DisplayName;
foreach (var pn in item.PhoneNumbers)
contact.Number = string.IsNullOrEmpty(contact.Number) ? pn.PhoneNumber : (contact.Number + " , " + pn.PhoneNumber);
foreach (var ea in item.EmailAddresses)
contact.Email = string.IsNullOrEmpty(contact.Email) ? ea.EmailAddress : (contact.Email + " , " + ea.EmailAddress);
phoneContact.Add(contact);
}
}
We are currently creating a Windows Store Application which gains information from an RSS feed and inputs this information into an ObservableCollection. The issue we are having is when the information is being gained, the Applications UI becomes unresponsive.
In order to get around this, I thought about creating a new thread and calling the method within this. Though, after some research we realised that this was no longer possible in Windows Store Apps. How can we get around this?
The method that collects the information is below.
public void getFeed()
{
setupImages();
string[] feedUrls = new string[] {
"http://www.igadgetos.co.uk/blog/category/gadget-news/feed/",
"http://www.igadgetos.co.uk/blog/category/gadget-reviews/feed/",
"http://www.igadgetos.co.uk/blog/category/videos/feed/",
"http://www.igadgetos.co.uk/blog/category/gaming/feed/",
"http://www.igadgetos.co.uk/blog/category/jailbreak-2/feed/",
"http://www.igadgetos.co.uk/blog/category/kickstarter/feed/",
"http://www.igadgetos.co.uk/blog/category/cars-2/feed/",
"http://www.igadgetos.co.uk/blog/category/software/feed/",
"http://www.igadgetos.co.uk/blog/category/updates/feed/"
};
{
try
{
XNamespace dc = "http://purl.org/dc/elements/1.1/";
XNamespace content = "http://purl.org/rss/1.0/modules/content/";
foreach (var feedUrl in feedUrls)
{
var doc = XDocument.Load(feedUrl);
var feed = doc.Descendants("item").Select(c => new ArticleItem() //Creates a copy of the ArticleItem Class.
{
Title = c.Element("title").Value,
//There are another 4 of these.
Post = stripTags(c.Element(content + "encoded").Value) }
).OrderByDescending(c => c.PubDate);
this.moveItems = feed.ToList();
foreach (var item in moveItems)
{
item.ID = feedItems.Count;
feedItems.Add(item);
}
}
lastUpdated = DateTime.Now;
}
catch
{
MessageDialog popup = new MessageDialog("An error has occured downloading the feed, please try again later.");
popup.Commands.Add(new UICommand("Okay"));
popup.Title = "ERROR";
popup.ShowAsync();
}
}
}
How would we be able to cause the Application to not freeze as we gain this information, as Threading is not possible within Windows Store Applications.
E.g - We planned to use;
Thread newThread = new Thread(getFeed);
newThread.Start
You need to use the well documented async pattern for your operations that happen on the UI thread. The link given by Paul-Jan in the comments is where you need to start. http://msdn.microsoft.com/en-us/library/windows/apps/hh994635.aspx