Xamarin API VK List forming - c#

I'm trying to do qualification job for a work and have some problems with realization of code on Xamarin.
I have such classes and functions. They're working on console of c# but not in xamarin. I don't know what to do. They give only freeze on Xamarin.
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace radacode.ActionForm
{
class ListMaker
{
public static List<Country> GetCountryList()
{
List<Country> result=new List<Country>();
Task<string> task =GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
JObject vk = JObject.Parse(task.GetAwaiter().GetResult());
foreach (JObject jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
public static async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
override public string ToString()
{
return Title;
}
}
}
}

When using Xamarin Forms, it's best to use Portable Class Projects rather than Shared. In my opinion.
Also it's important that Statics are not used especially for calls that are async. Think of Async as to being similar to AsyncTask in JAVA. They're none blocking.
public class ListMaker
{
public List<Country> GetCountyList()
{
return GetCountryListAsync().Result;
}
private async Task<List<Country>> GetCountryListAsync()
{
var result = new List<Country>();
var task =
await GetRequestAsync(#"http://api.vk.com/method/database.getCountries?need_all=1&v=5.60");
var vk = JObject.Parse(task);
foreach (var jsonCountry in vk["response"]["items"])
result.Add(JsonConvert.DeserializeObject<Country>(jsonCountry.ToString()));
return result;
}
private async Task<string> GetRequestAsync(string url)
{
using (var httpClient = new HttpClient())
return await httpClient.GetStringAsync(url);
}
public class Country
{
public int Cid { get; set; }
public string Title { get; set; }
public new string ToString()
{
return Title;
}
}
}
Now that you have your class, you can then create an instance of it and execute it.
NOTE:- the Async and Await in my example, or this one, is incorrect.
It should really bubble up to a parent class that has a property and a void in the class statement.
public async void TheLister()
{
var listMaker = new ListMaker();
var countryList = await listmaker.GetCountryListAsync();
// Do something with countryList
}

Related

async Lazy<T> getting results right away

I have the following:
public class User
{
private readonly Lazy<Task<List<ReminderDb>>> _reminders;
public SmsUserDb()
{
// Get _reminderReader from IoC
_reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>)await _reminderReader.Get(UserId));
}
public string UserId { get; set; }
public Task<List<ReminderDb>> Reminders => _reminders.Value;
}
When I instantiate an object Like so:
var n = new SmsUserDb {UserId = "123456"};
var rems = await n.Reminders;
This code works and I see that n.Reminders ="Waiting for activation" until I hit await n.Reminders line.
However, when I query this User object from cache like so:
var n1 = await _userReader.GetUserFromCache("+17084556675"); // return SmsUserDb
var n2 = await n1.Reminders;
when it hits GetUserFromCache() it right away calls _reminderReader.Get(UserId) which calls cache again to get reminders. Then it simply times out. So Lazy doesn't work and most likely causes a deadlock.
public async Task<SmsUserDb> GetUserFromCache(string phoneNumber)
{
var hash = CachedObjectType.smsuser.ToString();
var fieldKey = string.Format($"{CachedObjectType.smsuser.ToString()}:user-{phoneNumber}");
var result = await _cacheUserService.GetHashedAsync(hash, fieldKey);
return result;
}
private async Task<List<ReminderDb>> GetRemindersFromCache(string userId)
{
var hash = CachedObjectType.smsreminder.ToString();
var fieldKey = string.Format($"{CachedObjectType.smsreminder.ToString()}:user-{userId}");
var result = await _cacheService.GetHashedAsync(hash, fieldKey);
return result ?? new List<ReminderDb>();
}
What could be the problem?
This all works fine in my test code (shown below). Therefore the error must be in some code that you haven't shown us.
Here's some sample code that works - it proves that Lazy<T> is working correctly. Therefore the error is elsewhere in your code.
You must post a compilable repro in order for anyone to help you with this.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Demo
{
public class ReminderDb
{
public string Value;
}
public class ReminderReader
{
public async Task<List<ReminderDb>> Get(string userId)
{
Console.WriteLine("In Get() for " + userId);
await Task.Delay(1000);
Console.WriteLine("Returning from Get()");
return new List<ReminderDb>{new ReminderDb{Value = userId}};
}
}
public class Cache
{
public void Add(string key, SmsUserDb value)
{
_cache.Add(key, value);
}
public async Task<SmsUserDb> GetHashedAsync(string key)
{
await Task.Delay(1000);
return _cache[key];
}
readonly Dictionary<string, SmsUserDb> _cache = new Dictionary<string, SmsUserDb>();
}
public class SmsUserDb
{
readonly Lazy<Task<List<ReminderDb>>> _reminders;
readonly ReminderReader _reminderReader = new ReminderReader();
public SmsUserDb()
{
_reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>) await _reminderReader.Get(UserId));
}
public string UserId { get; set; }
public Task<List<ReminderDb>> Reminders => _reminders.Value;
}
static class Program
{
static async Task Main()
{
var db = new SmsUserDb(){UserId = "user ID"};
var cache = new Cache();
cache.Add("key", db);
Console.WriteLine("Press RETURN to await cache.GetHashedAsync()");
Console.ReadLine();
var result = await cache.GetHashedAsync("key");
Console.WriteLine("Press RETURN to await Reminders[0].Value");
Console.ReadLine();
Console.WriteLine((await result.Reminders)[0].Value);
}
}
}
Found the problem. I was using the same class to write to cache, that is:
public class User
{
private readonly Lazy<Task<List<ReminderDb>>> _reminders;
public SmsUserDb()
{
// Get _reminderReader from IoC
_reminders = new Lazy<Task<List<ReminderDb>>>(async () => (List<ReminderDb>)await _reminderReader.Get(UserId));
}
public string UserId { get; set; }
public Task<List<ReminderDb>> Reminders => _reminders.Value;
}
After using a different class for writing (below) and reading (above), all works as desired. thanks
public class CacheUser {
public string UserId { get; set; }
public List<ReminderDb> Reminders {get; set; }
}

How to correctly get all Items from DocumentDB via webapi

I have the following DocumentDB Repository helper class
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Web;
namespace TenantManagementWebApi.DataAccess
{
public static class DocumentDBRepository<T> where T : class
{
private static readonly string DatabaseId = ConfigurationManager.AppSettings["database"];
private static readonly string CollectionId = ConfigurationManager.AppSettings["collection"];
private static DocumentClient client;
public static async Task<T> GetItemAsync(string id)
{
try
{
Document document = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1 })
.Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
public static async Task<Document> CreateItemAsync(T item)
{
return await client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public static async Task<Document> UpdateItemAsync(string id, T item)
{
return await client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
public static async Task DeleteItemAsync(string id)
{
await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id));
}
public static void Initialize()
{
client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["endpoint"]), ConfigurationManager.AppSettings["authKey"]);
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
private static async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
private static async Task CreateCollectionIfNotExistsAsync()
{
try
{
await client.ReadDocumentCollectionAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await client.CreateDocumentCollectionAsync(
UriFactory.CreateDatabaseUri(DatabaseId),
new DocumentCollection { Id = CollectionId },
new RequestOptions { OfferThroughput = 1000 });
}
else
{
throw;
}
}
}
}
}
And I need to do the webapi crud controller for one entity:
public class Tenant
{
public string TenantId { get; set; }
public string TenantUrl { get; set; }
public string CertificatePath { get; set; }
public string CertificatePassword { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
I am not sure what to put in the Predicate to get all items which Are Tenant.
public async Task<List<Tenant>> GetTenants()
{
return await DocumentDBRepository<List<Tenant>>.GetItemsAsync(d => d. != null);
}
You need to make your generic T object more specific. Limit it to a class that implements an interface of some sort like ICosmosEntity and add a EntityType property on that interface.
Then make your DTOs implement that interface and set the EntityType to the class name. That way you are able to create a dynamic predicate that gets nameof(T) and automatically adds it in the Where clause of your LINQ query.
If you just wanna get all the items in the collection then in your code the x => true predicate will do that but it won't limit it in tenants unless the collection only has tenant objects in it.
Also ReadDocumentAsync will only worth that way when your collection has no partition key (which is not really recommended)
It might worth taking a look at Cosmonaut as it does exactly what you want and more. It supports the exact same collection sharing logic that you are trying to code.
Disclaimer, I am the creator of Cosmonaut.

C#. How can I pass my json deserializing method as Async?

So here's what I am trying to do and what I have accomplished.
private static T _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = w.DownloadString(url);
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
This method (when called) is used like so:
var onlineornot = ("http://blah.com");
var chatters = _getjson<Rootobject>(onlineornot);
<Rootobject> being a class set up like this:
public class Rootobject
{
public _Links _links { get; set; }
public int chatter_count { get; set; }
public Chatters chatters { get; set; }
public Stream stream { get; set; }
public Stream game { get; set; }
public _Links2 _links2 { get; set; }
}
For the most part, it works but it causes my app to hang every time I call _getJson. I was wondering how I could use Async in this case, while maintaining the ability to get the properties from <Rootobject>.
The WebClient class has a DownloadStringAsync() method (doc) you can use.
Here is a brief blog post that shows how you can use async/await to prevent your UI from blocking.
ex:
private static async Task<T> _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = await w.DownloadStringTaskAsync(url);
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
public async void Button1_Click(...)
{
...
var onlineornot = ("http://example.com");
var chatters = await _getjson<Rootobject>(onlineornot);
...
}
Quick answer, use WebClient.DownloadStringAsync method: https://msdn.microsoft.com/en-us/library/ms144202(v=vs.110).aspx
Modify your code like this:
private static async Task<T> _getjson<T>(string url) where T : new()
{
using (var w = new WebClient())
{
var json_data = string.Empty;
// attempt to download JSON data as a string
try
{
json_data = await w.DownloadStringTaskAsync(new Uri(url));
}
catch (Exception) { }
// if string with JSON data is not empty, deserialize it to class and return its instance
return !string.IsNullOrEmpty(json_data) ? JsonConvert.DeserializeObject<T>(json_data) : new T();
}
}
Also, the key thing here is to make sure this is not executed on the main UI thread.

HTTP response is never returned

I am building an app in Xamarin.Android ! which determines my Address using google Maps API when given a latitude and longitude. However my App fails to deliver an HTTP response. I don't receive any runtime errors and VS debugger behaves as if my App has hanged.
1> I don't know whether this is an issue of Xamarin.Android
2> As i read somehwere it could be an issue of blocking,asynchronous codes but then I use the same piece of code for my Windows App and it never gave me trouble
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace App_Code
{
public class myLocationProxy
{
public static async Task<RootObject_AutoLocationAddress> getmyLocation(string lat, string lng)
{
var http = new HttpClient();
/*CODE STOPS HERE*/var response = await http.GetAsync(String.Format("http://maps.google.com/maps/api/geocode/json?latlng={0},{1}&sensor=false", Uri.EscapeDataString(lat), Uri.EscapeDataString(lng)));
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject_AutoLocationAddress));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject_AutoLocationAddress)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class AddressComponent_AutoLocationAddress
{
[DataMember]
public string long_name { get; set; }
[DataMember]
public List<string> types { get; set; }
}
[DataContract]
public class Result_AutoLocationAddress
{
[DataMember]
public List<AddressComponent_AutoLocationAddress> address_components { get; set; }
[DataMember]
public string formatted_address { get; set; }
}
[DataContract]
public class RootObject_AutoLocationAddress
{
[DataMember]
public List<Result_AutoLocationAddress> results { get; set; }
[DataMember]
public string status { get; set; }
}
}
Try below code snippet just added TimeOut value.
public static async Task<RootObject_AutoLocationAddress> getmyLocation(string lat, string lng)
{
var client = new HttpClient()
{
Timeout = TimeSpan.FromMilliseconds(10000) //10 second, This line might help you
};
var response = await client.GetAsync(String.Format("http://maps.google.com/maps/api/geocode/json?latlng={0},{1}&sensor=false", Uri.EscapeDataString(lat), Uri.EscapeDataString(lng)));
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject_AutoLocationAddress));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject_AutoLocationAddress)serializer.ReadObject(ms);
return data;
}
Cheers!!

Running a Task from App.xaml.cs on the Windows Phone 8

I have the following task i would love to initialize once the app is running, and just populate a value in my App.xaml.cs
public partial class App : Application
{
public bool ProcessedTask = false;
public List<Item> Items = new List<Item>();
public App()
{
...
// Standard XAML initialization
InitializeComponent();
// NOW HERE I WOULD LIKE TO INVOKE MY TASK
}
public async Task<string> RequestDataTask()
{
HttpClient client = new HttpClient();
Task<string> getStringRequests = client.GetStringAsync("http://test.com/get/");
ItemsRootObject responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ItemsRootObject>(getStringRequests);
foreach (Item item in responseObject.rows)
{
Items.Add(item);
}
ProcessedTask = true;
string Message = "Processed Task";
return Message;
}
}
public class ItemsRootObject
{
public List<Item> rows { get; set; }
public bool success { get; set; }
public int code { get; set; }
public string msg { get; set; }
}
public class Item
{
public string value { get; set; }
}
I already know the JSON return and objects are there correctly (works in a regular call), but i don't know (understand) how to invoke my task while keeping the phone app going (load MainPage.xaml).
Anyone can tell how i get my task started asynchronously?
You can use async and await where you need to call the task.
private async void yourFunction(object sender, RoutedEventArgs e)
{
string result = await RequestDataTask();
}
http://msdn.microsoft.com/it-it/library/hh191443.aspx
But if you want to call an async method inside a constructor use something like this:
public partial class App
{
private readonly Task _initializingTask;
public App()
{
_initializingTask = Init();
}
private async Task Init()
{
/*
Initialization that you need with await/async stuff allowed
*/
string result = await RequestDataTask();
}
}

Categories