I am building a Windows Phone 8 application. For that I require to fetch contacts from People Hub App. Is there any way I can keep these contacts even after the application closes?
I have looked into data caching but if the contact has been updated then caching won't work.
This can be done.
I've implemented this with the Group Contacts app.
In my solution, I used SQLite to store contacts into various categories based on user preference.
When the app starts up, I initialize my local database using SQLite and pull contacts from there as well as retrieving all the contacts the phone itself.
Example:
await ContactsRepository.Instance.Initialize();
var appContacts = await ContactsRepository.Instance.Get();
var phoneContacts = await ContactServices.Instance.LoadContacts(Contacts, SelectedCategory);
MergeContacts(appContacts, phoneContacts);
.
.
When ever the app starts up, it needs to create a database if one does not already exist.
Example:
public async Task Initialize()
{
_connection = new SQLiteAsyncConnection(Constants.DATABASE_FILE_NAME);
await EnsureTableExist<ContactReference>(_connection);
}
private async Task EnsureTableExist<T>(SQLiteAsyncConnection connection) where T : new()
{
bool noTableExists = false;
try
{
var query = await connection.Table<T>().FirstOrDefaultAsync();
}
catch (SQLiteException ex)
{
if (ex.Message.Contains("no such table"))
{
noTableExists = true;
}
}
if (noTableExists)
{
await connection.CreateTableAsync<T>();
}
}
Windows 8.1 uses a ContactManager to retrieve contacts from the People Hub.
Example:
public async Task<ObservableCollection<Contact>> LoadContacts(ObservableCollection<Contact> contacts, Category category)
{
contacts.Clear();
try
{
var contactStore = await ContactManager.RequestStoreAsync();
var result = await contactStore.FindContactsAsync();
foreach (var item in result)
{
contacts.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return contacts;
}
Then I manage my contact collection between the phone's contact list and my app's contact list.
Example:
private void MergeContacts(ObservableCollection<ContactReference> appContacts, ObservableCollection<Contact> phoneContacts)
{
foreach (var contact in phoneContacts)
{
var contactExists = appContacts.Any(c => c.ContactId == contact.Id);
if (!contactExists)
{
OthersCategory.Contacts.Add(contact);
}
Category category = GetCategory(contact);
if (category == null)
{
OthersCategory.Contacts.Add(contact);
}
}
SortContacts(OthersCategory);
}
I created an entity class to support my local database operations.
Example:
public class ContactReference
{
[PrimaryKey]
public string ContactId { get; set; }
public string CategoryName { get; set; }
}
NOTE:
The emulator that VS2013 provides does not have a list of imaginary contacts.
As a result, I found testing easier by using my personal phone for debugging.
Related
I need to consume an API in my MVC project. the actions in API are secured, So you need to access a token (JWT) to consume it. I face an error every time I try to deserialize the response into the model (Player). It says *Could not cast or convert from System.String to MyMVC.Models.Player*
When I run a debugger, the piece of code including deserialization is in red in the internal server error page.
Here is the action in API
[HttpGet]
[Authorize]
public ActionResult<List<Player>> GetAllPlayers()
{
var players = _applicationDbContext.Players.OrderBy(p => p.Name).Select(p=> p.Name).ToList();
return Ok(players);
}
This is the action in the MVC project
public async Task<IActionResult> GetPlayers()
{
var token = HttpContext.Session.GetString("Token");
List<Player> players = new List<Player>();
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:53217/api/player");
var client = _clientFactory.CreateClient();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if(response.StatusCode == System.Net.HttpStatusCode.OK)
{
var strResponse = await response.Content.ReadAsStringAsync();
players = JsonConvert.DeserializeObject<List<Player>>(strResponse);
}
return View(players);
}
Sami Kuhmonen 's comment is right.
var players = _applicationDbContext.Players.OrderBy(p => p.Name).Select(p=> p.Name).ToList();
From here we can get name list not player list.
Name list contain string name. Player list contain object player1 {name="xx",age="xx"}
But
List<Player> players = new List<Player>();
var strResponse = await response.Content.ReadAsStringAsync();
players = JsonConvert.DeserializeObject<List<Player>>(strResponse);
here we need player list contain object players .
You can use below code in your API to get the playerlist.
var players = _applicationDbContext.Players.ToList();
I reproduce your problem. Then I use that method to solve it.
Update
Create a new class User contain the property that you want.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
Then use the below code
var players = _applicationDbContext.Players.Select (P=>new User { Name=P.Name, Id=P.Id} ).ToList();
In mvc change List<Player> players = new List<Player>(); to
List<User> players = new List<User>();
Result:
The story is that, I have ROOM Model class. I want to return json with using Signalr. Is it possible ? If it is, how can i use it ?
PS: And I know that I dont return room objet to clients.
public List<RoomModel> GetRooms()
{
GameUser user = _gameService.GetUserByClientId(Context.ConnectionId);
var room = _gameService.GetAllowedRooms(user).Select(r => new RoomModel
{
Name = r.Name,
Count = 0,
Private = r.Private,
Closed = r.Closed,
}).ToList();
return room;
}
SignalR will automatically serialize your objects when you are sending them over to client. (I assume your client is javascript.)
As you can see in this example They are sending ShapeModel complex object to be processed in javascript. The serialization is all automated.
If your method from your example is a hub method, I suggest you end it differently. Instead of returning value, you would probably call a client event. So:
public class RoomHub : Hub {
public void GetRooms() {
List<Room> rooms = new List<Room>();
rooms.Add( new Room{ Name = "Room1", Count = 12, Closed = true, Private = false});
rooms.Add( new Room{ Name = "Room2", Count = 20, Closed = false, Private = true});
// sending a list of room objects
Clients.Client(Context.ConnectionId).roomInfo(rooms);
}
}
// Room class (your complex object)
public class Room
{
public string Name { get; set; }
public int Count { get; set; }
public bool Private { get; set; }
public bool Closed { get; set; }
}
See details about calling from hub methods here.
Then javascript client:
var roomHub = $.connection.roomHub;
roomHub.client.roomInfo = function (rooms) {
// the parameter rooms is a serialized List<Room>
// which here will be an array of room objects.
console.log(rooms);
// You can read the room properties as well
for (i=0; i<rooms.length; ++i) {
console.log(rooms[i].Name);
console.log(rooms[i].Count);
}
}
$.connection.hub.start().done(function () {
console.log("You are connected");
roomHub.server.getRooms();
});
On my browser console:
I want to add more that one contacts to contact list from a xml file, but saveContactTask.Show();
added one contact to contact list, Please anyone tell me how to resolve this issue .
This is my code:
private void AddContacts(object sender, RoutedEventArgs e)
{
using (IsolatedStorageFile istf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream istfs = istf.OpenFile("MyContacts.xml",FileMode.Open))
{
XDocument doc = XDocument.Load(istfs);
var query = from d in doc.Root.Descendants("Contacts")
select new
{
firstName = d.Element("name").Value,
mobilePhone = d.Element("phone").Value
};
foreach (var po in query)
{
saveContactTask.FirstName = po.firstName;
saveContactTask.MobilePhone = po.mobilePhone;
saveContactTask.Show();
}
}
}
SaveContactTask class is designed to add only one contact at a time and Show() function is asynchronous. You can't add second contact until the first call will be finished. Your code should be rewritten to react on saveContactTask.Completed += new EventHandler<SaveContactResult>(saveContactTask_Completed); event and start adding the second(etc) contact only when the previous is finished. There is possibility, that new SaveContactTask should be used for the second(etc) contact, bear it in mind.
Try something like this (it's only a sample of idea):
private List<Contact> listToAdd;
private SaveContactTask saveTask;
saveTask.Completed += addComplete;
void addComplete(...)
{
if ( listToAdd.Count > 0 )
{
Contact contact = listToAdd[0];
listToAdd.RemoveAt(0);
saveTask. (set values from contact)
saveTask.Show();
}
}
I just wrote a simple windows 8 form that post to web service api. It works fine. But my challenge is been able to determine when the post operation was a success and a failure. I dont know how to return a value cos aysnc Task is not allowing a return type.
//This class does the post to web service
public class B2cMobileuserService : IB2cMobileuserService
{
private string RegisterUserUrl = RestfulUrl.RegisterMobileUser;
private readonly HttpClient _client = new HttpClient();
public async Task RegisterMobileUser(B2cMobileuserView user)
{
var jsonString = Serialize(user);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var result = await _client.PostAsync(RegisterUserUrl, content);
}
}
//This class calls the one above
public class WebserviceProcessor
{
//declaring all the service objects that would be used
IB2cMobileuserService mobileuserService = null;
public WebserviceProcessor() {
mobileuserService = new B2cMobileuserService();
}
//This method is going to post values to the web serever
public async void RegisterUser(B2cMobileuserView mobileuser) {
mobileuserService.RegisterMobileUser(mobileuser);
}
}
//Then the code below is from my .xaml user interface that calls the class that sends to webservice
private void Button_Click(object sender, RoutedEventArgs e)
{
B2cMobileuserView user = new B2cMobileuserView();
user.Name = name.Text;
user.Email = email.Text;
user.PhoneType = "Windows Mobile";
user.BrowserType = "None";
user.CountryName = "Nigeria";
user.UserPhoneID = phone.Text;
Serviceprocessor.RegisterUser(user);
progressBar.Visibility = Visibility.Visible;
}
Please I dont know how to return a value cos when I try I get the error that says async method must be void.
I need to set a way to know when the post was a success based on the return value from the web service.
To ensure the POST was successful, call HttpResponseMessage.EnsureSuccessStatusCode:
public async Task RegisterMobileUser(B2cMobileuserView user)
{
var jsonString = Serialize(user);
var content = new StringContent(jsonString, Encoding.UTF8, "application/json");
var result = await _client.PostAsync(RegisterUserUrl, content);
result.EnsureSuccessStatusCode();
}
If you want to return a value, use a Task<T> return type instead of Task.
On a side note, avoid async void; use async Task instead of async void unless the compiler forces you to write async void:
//This method is going to post values to the web serever
public Task RegisterUser(B2cMobileuserView mobileuser) {
return mobileuserService.RegisterMobileUser(mobileuser);
}
Also, you should name your asynchronous methods ending in *Async:
//This method is going to post values to the web serever
public Task RegisterUserAsync(B2cMobileuserView mobileuser) {
return mobileuserService.RegisterMobileUserAsync(mobileuser);
}
You may find my async intro and MSDN article on async best practices helpful.
I have a page where user can enter his name and attach an image.
When returning from tombstoning state, is it mandatory for my app to restore the image too?
Is it app certification requirement, something without which my app will not pass certification? Or is it a recommended pattern?
same question in the case when I have a pivot for example, is it mandatory to save the index of selected pivot item and restore the selection when activating from tombstoning?
Not necessary:
Is there a popular library \ framework to help me with tombstoning and serializing objects, images, etc?
According to the Technical certification requirements for Windows Phone , the only requirements are :
A Windows Phone app is deactivated when the user presses the Start button or if the device timeout causes the lock screen to engage. A Windows Phone app is also deactivated with it invokes a Launcher or Chooser API.
A Windows Phone OS 7.0 app is tombstoned (terminated) when it is deactivated. A Windows Phone OS 7.1 or higher app becomes Dormant when it is deactivated but can be terminated by the system when resource use policy causes it to tombstone.
When activated after termination, the app must meet the requirements in Section 5.2.1 – Launch time.
As the section 5.2.1 - "Launch time" only concerns startup performance and responsiveness, you don't have a certification requirement for your issue.
However, if the user enters data (attaches images, etc.) and let's say it answer a call, does some other stuff and get's back to the application and then the data he entered was lost... it surely won't appreciate it. That will look more like a defect/bug.
Concerning the serialization of your state, I recommend you to use binary serialization as the performance is at least 10x better than using Json, Xml or any other format.
Personally, I implement a custom interface, IBinarySerializable to my "state" related classes and use this BinaryWriter extensions class to help writing the serialization code:
using System.IO;
namespace MyCompany.Utilities
{
public interface IBinarySerializable
{
void Write(BinaryWriter writer);
void Read(BinaryReader reader);
}
}
using System;
using System.Collections.Generic;
using System.IO;
namespace MyCompany.Utilities
{
public static class BinaryWriterExtensions
{
public static void Write<T>(this BinaryWriter writer, T value) where T : IBinarySerializable
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
value.Write(writer);
}
public static T Read<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
if (reader.ReadBoolean())
{
T result = new T();
result.Read(reader);
return result;
}
return default(T);
}
public static void WriteList<T>(this BinaryWriter writer, IList<T> list) where T : IBinarySerializable
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (T item in list)
{
item.Write(writer);
}
}
public static List<T> ReadList<T>(this BinaryReader reader) where T : IBinarySerializable, new()
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<T> list = new List<T>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
T item = new T();
item.Read(reader);
list.Add(item);
}
return list;
}
}
return null;
}
public static void WriteListOfString(this BinaryWriter writer, IList<string> list)
{
if (list == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(list.Count);
foreach (string item in list)
{
writer.WriteSafeString(item);
}
}
public static List<string> ReadListOfString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
{
int count = reader.ReadInt32();
List<string> list = new List<string>(count);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
list.Add(reader.ReadSafeString());
}
return list;
}
}
return null;
}
public static void WriteSafeString(this BinaryWriter writer, string value)
{
if (value == null)
{
writer.Write(false);
return;
}
writer.Write(true);
writer.Write(value);
}
public static string ReadSafeString(this BinaryReader reader)
{
bool hasValue = reader.ReadBoolean();
if (hasValue)
return reader.ReadString();
return null;
}
public static void WriteDateTime(this BinaryWriter writer, DateTime value)
{
writer.Write(value.Ticks);
}
public static DateTime ReadDateTime(this BinaryReader reader)
{
var int64 = reader.ReadInt64();
return new DateTime(int64);
}
}
}