How to receive response from server in Xamarin.Forms - xamarin

I have created an HTTP Client that sends data to my server. This data will query my server that will return a JSON object. How can I receive the JSON Object response from my server and insert it into my database?
The code below will send a ContactID to my server and my server will return a JSON Object How can I get the JSON Object from my server? What will I add to my code? I have added
var data = await response.Content.ReadAsStringAsync();
but I don't know how to proceed.
try
{
var db = DependencyService.Get<ISQLiteDB>();
var conn = db.GetConnection();
var sql = "SELECT * FROM tblUser WHERE ContactID = '" + contact + "'";
var getUser = conn.QueryAsync<UserTable>(sql);
var resultCount = getUser.Result.Count;
//Check if the user has been sync
if (resultCount < 1)
{
try
{
syncStatus.Text = "Syncing user to server...";
var link = Constants.requestUrl + "Host=" + host + "&Database=" + database + "&Contact=" + contact + "&Request=8qApc8";
string contentType = "application/json";
JObject json = new JObject
{
{ "ContactID", contact }
};
HttpClient client = new HttpClient();
var response = await client.PostAsync(link, new StringContent(json.ToString(), Encoding.UTF8, contentType));
var data = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
var userresult = JsonConvert.DeserializeObject<IList<UserData>>(content);
var count = userresult.Count;
for (int i = 0; i < count; i++)
{
try
{
syncStatus.Text = "Syncing user to server...";
var item = userresult[i];
var contactID = item.ContactID;
var userID = item.UserID;
var userPassword = item.UserPassword;
var userType = item.UserType;
var userStatus = item.UserStatus;
var lastSync = item.LastSync;
var serverUpdate = item.ServerUpdate;
var mobileUpdate = item.MobileUpdate;
var user = new UserTable
{
ContactID = Convert.ToInt32(contactID),
UserID = userID,
UserPassword = userPassword,
UserType = userType,
UserStatus = userStatus,
LastSync = lastSync,
ServerUpdate = serverUpdate,
MobileUpdate = mobileUpdate
};
await conn.InsertAsync(user);
}
catch (Exception ex)
{
Console.Write("Syncing user error " + ex.Message);
}
}
}
}
catch (Exception ex)
{
Console.Write("Syncing User Error " + ex.Message);
}
}
My PHP code will query my database with the ContactID received from Xamarin HTTP Client.
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$ContactID = $json_obj->ContactID;
$sql = "SELECT * FROM tblUser WHERE ContactID = '$ContactID'";
$result = mysqli_query($conn, $sql);
$count = mysqli_num_rows($result);
if($count > 0){
while ($row = #mysqli_fetch_array($result)) {
$decr = CryptRC4(FromHexDump($row['UserPassword']), $key);
$ar[] = array(
'ContactID' => $row['ContactID'],
'UserID' => $row['UserID'],
'UserPassword' => $decr,
'UserType' => $row['UserType'],
'UserStatus' => $row['UserStatus'],
'LastSync' => $sync,
'ServerUpdate' => $row['ServerUpdate'],
'MobileUpdate' => $row['MobileUpdate']
);
print json_encode($ar);
//Update LastSync DateTime
$sql = "UPDATE tblUser SET LastSync = '$sync' WHERE ContactID = '$ContactID'";
mysqli_query($conn, $sql);
}
}

Last statement in your example above gives list of json objects in string format.
var data = await response.Content.ReadAsStringAsync();
You need to convert that back to list of objects. To let your project know about definition of the object, create a plain class with public properties (Something like below)
public class UserLog
{
public int ContactId { get; set; }
public string Log { get; set; }
public DateTime LogDate { get; set; }
}
Add Newtonsoft.Json (by James Newton-King) Nuget package to your project so that you can work with json.
To convert content of the variable 'data' into list of UserLog objects, write code like
var list = NewtonsoftUtil<IList<UserLog>>.DeserializeObject(data);
(Add using Newtonsoft.Json; at top of the file)
Please let me know if this helps.

The answers above missing one important point -> efficiency.
There is no need to allocate a string in memory, especially if your JSON is big. Streams can do much better then strings:
// Read the response as stream
var stream = await response.Content.ReadAsStreamAsync();
// Use the next method for deserialization
T DeserializeJsonFromStream<T>(Stream stream)
{
if (stream == null || stream.CanRead == false)
return default(T);
using (var sr = new StreamReader(stream))
using (var jtr = new JsonTextReader(sr))
{
var js = new JsonSerializer();
return js.Deserialize<T>(jtr);
}
}
P.S.: Code example is bases on Json.NET.
P.S.S.: There are many good articles on this topic, I could recommend to get familiar with the next one.

Assuming that you have done everything correctly. In other words, You're be able to sent your contactID and get back a json.
Let's say your json structure is something like:
{"firstname" : "Doe",
"lastname" : "foo"
"age" : "27"}
One possible way to retrieve the data is as below:
using Newtonsoft.Json;
//after PostAsync()
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
JObject jContent = (JObject)JsonConvert.DeserializeObject(content);
string firstName = (string)jContent.GetValue("firstname")
string lastName = (string)jContent.GetValue("lastname");
int age = (int)jContent.GetValue("age");
}
Newtonsoft is available on Nuget. you need to install it if you have not done so.
Improved solution
What if your json has many key/values pairs like below:
{ key1 : value1,
key2 : value2,
key3 : value3,
...
key10 : value10}
Then it is not a good idea by doing :
string foo1 = (string)jContent.GetValue("key1");
string foo2 = (string)jContent.GetValue("key2");
//...
string foo10 = (string)jContent.GetValue("key10");
To handle this case, you can create a class:
public class Foo
{
public string Foo1 {get;set;}
public string Foo2 {get;set;}
//...
public string Foo2 {get;set;}
}
Then, you can do as simple as below:
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
Foo foo = JsonConvert.DeserializeObject<Foo>(content);
}
The improved solution referecnced from www.newtonsoft.com. Go there and check out other ways of using the library.

Related

xamarin.forms - Upload multiple images and files using multipart/form data

In my xamarin.forms app. I am using Media.plugin to select images from gallery and camera.And also file picker plugin to select files like pdf,jpg etc from file manager.User can select multiple images and files and It will store in an observable collection.In this observable collection I have the path of images as well as files. Where I am stuck is I want to send these data to rest API by using multipart/form data.How can I send these multiple files to the server? Any help is appreciated.
My ObservableCollection
public ObservableCollection<SelectedDocumentModel> DataManager
{
get
{
return _selectedfile ?? (_selectedfile = new ObservableCollection<SelectedDocumentModel>());
}
}
My Data Model
public class SelectedDocumentModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string FileName { get; set; }
public string Path { get; set; }
public ImageSource SelectedImage { get; set; }
public object Tasks { get; internal set; }
private bool isLoadingVisible = false;
public bool IsLoadingVisible
{
get
{
return isLoadingVisible;
}
set
{
if (value != null)
{
isLoadingVisible = value;
NotifyPropertyChanged("IsLoadingVisible");
}
}
}
}
Selecting image using media.plugin and allocating to my observable collection
var Filename = Path.GetFileName(file.Path);
var FilePath = file.Path;
var newList = new SelectedDocumentModel()
{
FileName = Filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path = FilePath
};
DataManager.Add(newList);
Selecting file from file manager using filepicker plugin and assign to observablecollection
var FilePath = pickedFile.FilePath;
var newList = new SelectedDocumentModel()
{
FileName = filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path= FilePath
};
DataManager.Add(newList);
EDIT
This is what I should do using httpclient.Currently these are written using RestSharp.
var client = new RestClient("{{api_url}}/MYData");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "bearer {{token}}");
request.AddHeader("Content-Type", "application/json");
request.AlwaysMultipartFormData = true;
request.AddParameter("ids", " [{\"id\":1,\"person_id\":5}]");
request.AddParameter("title", " Test");
request.AddParameter("description", " Test");
request.AddParameter("send_text_message", " true");
request.AddParameter("text_message", " Test");
request.AddParameter("notification_type"," global");
request.AddParameter("my_files", "[
{
\"name\": \"abc.jpg\",
\"key\": \"1583307983694\"
}
]");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
What I have done by the way suggested by Lucas Zhang - MSFT.
try {
MultipartFormDataContent multiContent = new MultipartFormDataContent();
foreach (SelectedDocumentModel model in SelectedFileData)
{
byte[] byteArray = Encoding.UTF8.GetBytes(model.Path);
MemoryStream stream = new MemoryStream(byteArray);
HttpContent fileStreamContent1 = new StreamContent(stream);
fileStreamContent1.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
Name = model.FileName,
FileName = model.FileName
};
fileStreamContent1.Headers.ContentType = new
System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
multiContent.Add(fileStreamContent1);
}
multiContent.Add(new StringContent(notificationdetails[0]), "title");
multiContent.Add(new StringContent(notificationdetails[1]), "description");
multiContent.Add(new StringContent(notificationdetails[3]), "type");
multiContent.Add(new StringContent(notificationdetails[7]), "send_text_message");
multiContent.Add(new StringContent(notificationdetails[2]), "text_message");
multiContent.Add(new StringContent(notificationdetails[8]), "send_email");
multiContent.Add(new StringContent(notificationdetails[9]), "notification_type");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("bearer",Settings.AuthToken);
var response = await client.PostAsync(url, multiContent);
var responsestr = response.Content.ReadAsStringAsync().Result;
await DisplayAlert("Result", responsestr.ToString(), "ok");
}
catch (Exception ex)
{
await DisplayAlert("Result", ex.Message.ToString(), "ok");
}
unfortunately it not working.It not sending the data as I intend.
How can I upload each files as multipart/formdata on a button click.?Any help is appriciated.
You could use MultipartFormDataContent to add multiple images,and use ContentDispositionHeaderValue.Parameters to add the values of your Data.
Usage
var fileStream = pickedFile.GetStream();
var newList = new SelectedDocumentModel()
{
FileName = filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path= FilePath,
Data = fileStream ,
};
MultipartFormDataContent multiContent = new MultipartFormDataContent();
foreach(var SelectedDocumentModel model in DataManager)
{
HttpContent fileStreamContent1 = new StreamContent(model.Data);
fileStreamContent1.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
Name = "File",
FileName = "xxx.jpg"
};
fileStreamContent1.Headers.ContentType = new
System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
multiContent.Add(fileStreamContent1);
multiContent.Add(new StringContent(model.Title), "model.Title");
multiContent.Add(new StringContent(model.Description), "model.Description");
multiContent.Add(new StringContent(model.Detail), "model.Detail");
}
// Send (url = url of api) ,use httpclient
var response = await client.PostAsync(url, multiContent);

How to get a CNContact phone number(s) as string in Xamarin.ios?

I am attempting to retrieve the names and phone number(s) of all contacts and show them into tableview in Xamarin.iOS. I have made it this far:
var response = new List<ContactVm>();
try
{
//We can specify the properties that we need to fetch from contacts
var keysToFetch = new[] {
CNContactKey.PhoneNumbers, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses
};
//Get the collections of containers
var containerId = new CNContactStore().DefaultContainerIdentifier;
//Fetch the contacts from containers
using (var predicate = CNContact.GetPredicateForContactsInContainer(containerId))
{
CNContact[] contactList;
using (var store = new CNContactStore())
{
contactList = store.GetUnifiedContacts(predicate, keysToFetch, out
var error);
}
//Assign the contact details to our view model objects
response.AddRange(from item in contactList
where item?.EmailAddresses != null
select new ContactVm
{
PhoneNumbers =item.PhoneNumbers,
GivenName = item.GivenName,
FamilyName = item.FamilyName,
EmailId = item.EmailAddresses.Select(m => m.Value.ToString()).ToList()
});
}
BeginInvokeOnMainThread(() =>
{
tblContact.Source = new CustomContactViewController(response);
tblContact.ReloadData();
});
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
and this is my update cell method
internal void updateCell(ContactVm contact)
{
try
{
lblName.Text = contact.GivenName;
lblContact.Text = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
//var no = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
//NSString a = new NSString("");
// var MobNumVar = ((CNPhoneNumber)contact.PhoneNumbers[0]).ValueForKey(new NSString("digits")).ToString();
var c = (contact.PhoneNumbers[0] as CNPhoneNumber).StringValue;
}
catch(Exception ex)
{
throw ex;
}
}
I would like to know how to retrieve JUST the phone number(s) as a string value(s) i.e. "XXXXXXXXXX". Basically, how to call for the digit(s) value.
this line of code
lblContact.Text = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
throw a run time exception as specified cast is not valid
Yes, exception is correct. First of all, you don't need any casts at all, contact.PhoneNumbers[0] will return you CNLabeledValue, so you just need to write it in next way
lblContact.Text = contact.PhoneNumbers[0].GetLabeledValue(CNLabelKey.Home).StringValue
//or
lblContact.Text = contact.PhoneNumbers[0].GetLabeledValue(CNLabelPhoneNumberKey.Mobile).StringValue
or you may try, but not sure if it works
contact.PhoneNumbers[0].Value.StringValue
I got solution. Here is my code if any one required.
CNLabeledValue<CNPhoneNumber> numbers =
(Contacts.CNLabeledValue<Contacts.CNPhoneNumber>)contact.PhoneNumbers[0];
CNPhoneNumber number = numbers.Value;
string str = number.StringValue;
lblContact.Text = str;

Dynamics CRM Solution Import via SDK is not working

I have the below code that imports a solution into CRM Dynamics.
The code executes successfully and the import job data returns a result of success. How ever when I look for the solution in Settings->Solutions it is not there. Can anyone suggest a fix?
private void ImportSolution(string solutionPath)
{
byte[] fileBytes = File.ReadAllBytes(solutionPath);
var request = new ImportSolutionRequest()
{
CustomizationFile = fileBytes,
ImportJobId = Guid.NewGuid()
};
var response = _settings.DestinationSourceOrgService.Execute(request);
var improtJob = new ImportJob(_settings);
var importJobResult = improtJob.GetImportJob(request.ImportJobId);
var data = importJobResult.Attributes["data"].ToString();
var jobData = new ImportJobData(data);
var filePath = $#"{this._settings.SolutionExportDirectory}\Logs\";
var fileName = $#"{filePath}{jobData.SolutionName}.xml";
Directory.CreateDirectory(filePath);
File.WriteAllText(fileName, data);
PrintResult(jobData.Result, jobData.SolutionName);
}
public class ImportJob
{
private readonly ConfigurationSettings _settings;
public ImportJob(ConfigurationSettings settings)
{
_settings = settings;
}
public Entity GetImportJob(Guid importJobId)
{
var query = new QueryExpression
{
EntityName = "importjob",
ColumnSet = new ColumnSet("importjobid", "data", "solutionname"),
Criteria = new FilterExpression()
};
var result = _settings.DestinationSourceOrgService.Retrieve("importjob", importJobId, new ColumnSet("importjobid", "data", "solutionname", "progress"));
return result;
}
}
Thre ImportSolutionResponse does not contain any information as per the screen shot below.

How to use RESTful service in Xamarin.Forms to fetch JSON data

Since I am new to Xamarin, I would really appreciate if someone could explain me how to consume RESTful service (returning JSON data) using Xamarin Forms with the simplest example.
You can use JSON.net and HTTP request, here is a quick example of how to use the movie database which is a free movie database GET and POST examples, hope this helps:
const string _baseUrl = "http://api.themoviedb.org/3/";
const string _pageString = "&page=";
//GET Example
public static async Task<ObservableCollection<Movie>> GetTopRatedMoviesAsync(int page = 1)
{
HttpClient client = new HttpClient();
//_apiKey = themoviedb api key, page = page size 1 = first 20 movies;
string topRatedUrl = _baseUrl + "movie/top_rated?" + _apiKey + _pageString + page;
HttpResponseMessage result = await client.GetAsync (topRatedUrl, CancellationToken.None);
if (result.IsSuccessStatusCode) {
try{
string content = await result.Content.ReadAsStringAsync ();
ObservableCollection<Movie> MovieList = GetJsonData(content);
//return a ObservableCollection to fill a list of top rated movies
return MovieList;
}catch(Exception ex){
//Model Error
Console.WriteLine (ex);
return null;
}
}
//Server Error or no internet connection.
return null;
}
static ObservableCollection<Movie> GetJsonData(string content){
JObject jresponse = JObject.Parse (content);
var jarray = jresponse ["results"];
ObservableCollection<Movie> movieList = new ObservableCollection<Movie> ();
foreach (var jObj in jarray) {
Movie newMovie = new Movie();
newMovie.Title = (string)jObj["title"];
newMovie.PosterPath = _baseImgUrl + (string)jObj["poster_path"];
newMovie.HighResPosterPath = _baseImgUrl + (string)jObj["poster_path"];
newMovie.Id = (int)jObj["id"];
newMovie.Overview = (string)jObj["overview"];
newMovie.VoteCount = (double)jObj["vote_count"];
newMovie.ReleaseDate = (DateTime)jObj["release_date"];
newMovie.VoteAverage = (float)jObj["vote_average"];
movieList.Add(newMovie);
}
return movieList;
}
//POST Example:
public static async Task<bool> PostFavoriteMovieAsync(Movie movie)
{
try
{
HttpClient client = new HttpClient();
//_sessionId = string with the movie database session.
string tokenUrl = _baseUrl + "account/id/favorite?" + _apiKey + _sessionId;
string postBody = JsonConvert.SerializeObject(new Favorite{
favorite = !movie.Favorite,
media_id = movie.Id,
});
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsync (tokenUrl,
new StringContent (postBody, Encoding.UTF8, "application/json"));
if(response.IsSuccessStatusCode)
return true;
else
return false;
}
catch(Exception ex){
Console.WriteLine (ex.Message);
return false;
}
}

Web Site Cannot implicitly convert type 'int' to 'string'

just started to use web services of Visual Studio
on my data base my user_id value is nvarchar() I want to select it and serve as a method on my URL The mistak line is below inside my method.
Would be very helpfull to have any solution. Thank you.
[WebMethod]
public string GetContant(string id)
{
var json = "";
var contact = from result in dc.mezura_users
where result.user_id = Int32.Parse(id) // here is my mistake
select result;
JavaScriptSerializer jss = new JavaScriptSerializer();
json = jss.Serialize(contact);
return json;
}
}
Try this:
[WebMethod]
public string GetContant(string id)
{
var json = "";
var newid = Int32.Parse(id);
var contact = from result in dc.mezura_users
where result.user_id = newid // here is my mistake
select result;
JavaScriptSerializer jss = new JavaScriptSerializer();
json = jss.Serialize(contact);
return json;
}

Resources