ListView in Xamarin using RestApi - json

I'm enable to solve this error. I wanted to display ListView of API data which is in large amount.
For example API contains this type of data :
[{"id":"666","employee_name":"xyz","employee_salary":"123","employee_age":"23","profile_image":""}]
Error screenshot:
Class.cs which i made after converting JSON to c#
public class employees
{
public string id { get; set; }
public string employee_name { get; set; }
public string employee_salary { get; set; }
public string employee_age { get; set; }
public string profile_image { get; set; }
}
This is the XAML.cs file where LoadData() is using for calling API
public async void LoadData()
{
var content = "";
HttpClient client = new HttpClient();
var RestURL = "MY API";
client.BaseAddress = new Uri(RestURL);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(RestURL);
content = await response.Content.ReadAsStringAsync();
var Items = JsonConvert.DeserializeObject<List<employees>>(content);
ListView1.ItemsSource = Items;
}
This is the XAML file of Xamarin.Forms:
<StackLayout BackgroundColor="White">
<ListView x:Name="ListView1" RowHeight="60">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Padding="8,0,8,0">
<Label Text="{Binding id}" TextColor="#000" FontSize="14" LineBreakMode="TailTruncation" />
<Label Text="{Binding employee_name}" TextColor="#000" LineBreakMode="TailTruncation" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>

First need to create a local model class :
public class TodoItem
{
public string id { get; set; }
public string employee_name { get; set; }
public string employee_salary{ get; set; }
public bool employee_age { get; set; }
public bool profile_image { get; set; }
}
And in the RestService can use TodoItem:
public List<TodoItem> Items { get; private set; }
public async Task<List<TodoItem>> RefreshDataAsync ()
{
Items = new List<TodoItem> ();
// RestUrl = http://developer.xamarin.com:8081/api/todoitems
var uri = new Uri (string.Format (Constants.RestUrl, string.Empty));
try {
var response = await client.GetAsync (uri);
if (response.IsSuccessStatusCode) {
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
}
} catch (Exception ex) {
Debug.WriteLine (#"ERROR {0}", ex.Message);
}
return Items;
}
And last where your listview itemsource can set as follow:
listView.ItemsSource = await RestService.RefreshDataAsync();
Note: Here is a official sample you can refer to.
I'm enable to solve this error, i wanted to display listview of API data which is in large amount
Showing large data in listview,here is a paging show method.After getting API data, saving them in local CacheListData.Not directly set it to listView.ItemsSource .And you need create a ItemListData to add data from CacheListData.Which the count of added data according to you once want to show.When listview scroll to bottom ,then show Add More Swipe method to reload next page data.
Generally, Solution is to cache lagre data to local first.Then get data a little by page to show.Here is a solution link can refer to.

You are using the wrong endpoint, you should use this one, to retrieve a list of employees
var RestURL = "http://dummy.restapiexample.com/api/v1/employees/";
You can check the API documentation

Related

Xamarin - Fill ListView with MySql Data

I'm kind of stuck and not getting anywhere. Here is my problem:
I want to populate a ListView with the data from a MySql database. Here is my class which contains the database queries:
DBConnection:
public ObservableRangeCollection<ExpenseReport> GetDataExpenseReport()
{
if (OpenConnection() == true)
{
DataExpense = new ObservableRangeCollection<ExpenseReport>();
MySqlCommand sc = new MySqlCommand();
sc.CommandText = "SELECT * FROM t_expensereport WHERE c_inputuser = #userid";
sc.Parameters.AddWithValue("#userid", User.Id);
sc.Connection = myConn;
MySqlDataReader dr = sc.ExecuteReader();
while (dr.Read())
{
DataExpense.Add(new ExpenseReport
{
Date = (DateTime)dr["c_date"],
Reason = (string)dr["c_reason"],
TripThereAndBack = (string)dr["c_tripThereAndBack"],
Vehicle = (string)dr["c_vehicle"],
Kilometers = (double)dr["c_kilometers"],
EuroProKm = (double)dr["c_euroProKm"],
TripCost = (double)dr["c_tripCost"],
Maut = (double)dr["c_maut"],
ParkingLot = (double)dr["c_parkingLot"],
Other = (double)dr["c_other"],
Accommodation = (double)dr["c_accommodation"],
Meal = (double)dr["c_meal"],
TrainTicket = (double)dr["c_trainTicket"]
});
}
dr.Close();
return DataExpense;
}
return null;
}
My Model ExpenseReport:
public class ExpenseReport
{
public DateTime Date { get; set; }
public string Reason { get; set; }
public string TripThereAndBack { get; set; }
public string Vehicle { get; set; }
public double Kilometers { get; set; }
public double EuroProKm { get; set; }
public double TripCost { get; set; }
public double Maut { get; set; }
public double ParkingLot { get; set; }
public double Other { get; set; }
public double Accommodation { get; set; }
public double Meal { get; set; }
public double TrainTicket { get; set; }
}
View:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:Magazin.ViewModels.Dashboard"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:model="clr-namespace:Magazin.Models"
x:Class="Magazin.Views.Dashboard.OverviewExpenseReportView"
Title="Übersicht Spesen">
<ContentPage.BindingContext>
<viewmodels:OverviewExpenseReportViewModel/>
</ContentPage.BindingContext>
<ContentPage.Behaviors>
<xct:EventToCommandBehavior
EventName="Appearing"
Command="{Binding RefreshCommand}" />
</ContentPage.Behaviors>
<ContentPage.Content>
<StackLayout>
<ListView
x:Name="OverviewER"
CachingStrategy="RecycleElement"
BackgroundColor="Transparent"
ItemsSource="{Binding ExpenseReport}"
HasUnevenRows="True"
SeparatorVisibility="None"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
RefreshControlColor="Green"
RefreshCommand="{Binding RefreshCommand}">
<!---->
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:ExpenseReport">
<ViewCell>
<Grid Padding="10">
<Frame CornerRadius="20" HasShadow="True">
<StackLayout Orientation="Horizontal">
<StackLayout Padding="20,0,0,0">
<StackLayout>
<Label Text="{Binding Reason}" FontSize="Medium" VerticalOptions="Center" TextColor="Green" />
</StackLayout>
<StackLayout>
<Label Text="{Binding Kilometers, StringFormat='{}{0}km'}" FontSize="Small" VerticalOptions="Center"/>
<Label Text="{Binding Date, StringFormat='{0:dd.MM.yyyy}'}" FontSize="Small" VerticalOptions="Center"/>
<Label Text="{Binding TripCost}" FontSize="Small" VerticalOptions="Center"/>
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Viewmodel OverviewExpenseReportViewModel
public class OverviewExpenseReportViewModel : ViewModelBase
{
public ObservableRangeCollection<ExpenseReport> ExpenseReportCollection { get; set; }
public AsyncCommand RefreshCommand { get; }
public OverviewExpenseReportViewModel()
{
RefreshCommand = new AsyncCommand(Refresh);
}
async Task Refresh()
{
ExpenseReportCollection = new ObservableRangeCollection<ExpenseReport>();
DBConnection db = new DBConnection();
await Task.Delay(1500);
ExpenseReportCollection.Clear();
ExpenseReportCollection.AddRange(db.GetDataExpenseReport());
}
}
I have long asked our friend Google but I somehow do not get anywhere. At this point
ExpenseReport.AddRange(db.GetDataExpenseReport()); I get the error that System.NullReferenceException: 'Object reference not set to an instance of an object.'
Can anyone help me on how I manage to populate the ListView, I appreciate any answers!
Lastly, I switched everything to ObservableRangeCollection from the MvvmHelpers dependency. But I always get this error, something I am doing wrong.
you are declaring ExpenseReport
public ObservableRangeCollection<ExpenseReport> ExpenseReport { get; set; }
but it will be null until you instantiate it
ExpenseReport = new ObservableRangeCollection<ExpenseReport>();
System.InvalidCastException: 'Specified cast is not valid.. Is
something wrong with that Line?
ExpenseReport.AddRange(db.GetDataExpenseReport());``
For this problem, you need to recheck the data type of the returned list and the object included in the returned list.
Suppose the returned type is IList<object>, then you cast IList<object> to List<ExpenseReport>,just as follows:
//initialize variable `ExpenseReport` here
ExpenseReportCollection = new ObservableRangeCollection<ExpenseReport>();
//suppose `data` is the returned data list
ExpenseReportCollection.AddRange(data as List<ExpenseReport>);
Suppose the type of returned Object(OtherObject) is not the same object(ExpenseReport), you need to iterate through the returned list one by one and then convert the returned Object to object ExpenseReport.

How to update table using query parameter in Html Agility Pack using C#

I've been parsing this Url with Html Agility Pack:
http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_quotes_settlements_options.html"
The default table displayed is always the closest contract date and the current date.
I have no problem parsing the complete page above but if I ask for another date I can't seem to get a new table when I add a query parameter to get another date:
eg. http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_quotes_settlements_options.html?tradeDate=03/07/2018"
This still returns the table for the current date. ie. 03/08/2018
However it does work if I add another query for contract month as well:
eg. http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_quotes_settlements_options.html?optionExpiration=190-M18&tradeDate=03/07/2018"
But if I then query:
eg. http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_quotes_settlements_options.html?optionExpiration=190-M18&tradeDate=03/06/2018"
....it will not give me the table for 03/06/2018.
It only appears to update the html for me when I change two or more query parameters in the Url. I'm fairly much a Noob with Html so I'm not sure if it's something to do with the actual website 'blocking' my request. Or does it expect some 'user interaction'?
The very 'basic' core of my code is:
using HtmlAgilityPack;
HtmlDocument htmlDoc = new HtmlDocument { OptionFixNestedTags = true };
HtmlWeb web = new HtmlWeb();
htmlDoc = web.Load(url);
A step in the right direction would be great.
Thank you.
Its a ajax site. the WepPage contains JS that makes Ajax queries by filtering done.
Therefore you do not need the html-agility-pack but the JSON.NET.
the URL is:
http://www.cmegroup.com/CmeWS/mvc/Settlements/Options/Settlements//190/OOF?monthYear=LOM18&strategy=DEFAULT&tradeDate=03/08/2018&pageSize=50&_=1520581128693
you need build the url query string, download th text with WebClient.DownloadString and convert it to POCO with JSON.NET.
Okay, so I've posted this answer for anyone else reading this post. Please feel free to comment or edit the post. Thanks again to Dovid for the suggestions. I cannot vouch for absolute syntax validity, however it's pretty close. The code loads a webpage table in Json format then saves to a file. There is a method for loading from the Json file as well. The code is 'as-is' and is not meant to be a copy and paste job, just a reference to how I did it.
using Newtonsoft;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
private string _jsonStr;
private string _tableUrlStr = "http://www.cmegroup.com/CmeWS/mvc/Settlements/Options/Settlements//190/OOF?monthYear=LOM18&strategy=DEFAULT&tradeDate=03/08/2018&pageSize=50&_=1520581128693";
using (WebClient wc = new WebClient)
{
wc.BaseAddress = #"http://www.cmegroup.com/";
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
wc.Headers[HttpRequestHeader.Accept] = "application/json";
_jsonStr = wc.DownloadString(_tableUrlStr);
}
if (_jsonStr.IsNullOrEmpty())
return;
JObject jo = JObject.Parse(_jsonStr);
//## Add some more detail to the Json file.
jo.Add("instrumentName", "my instrument name");
jo.Add("contract", "my contract name");
//## For easier debugging but larger file size.
_jsonStr = jo.ToString(Formatting.Indented);
//## Json to file:
string path = directoryString + fileString + ".json";
if (!Directory.Exists(directoryString))
{
Directory.CreateDirectory(directoryString);
}
if (File.Exists(path))
{
return;
}
using (FileStream fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
{
using (var streamWriter = new StreamWriter(fileStream, Encoding.UTF8))
{
streamWriter.WriteLine(_jsonStr);
streamWriter.Close();
}
}
//## Json file to collection:
//## Can copy and paste your Json at 'www.json2csharp.com'.
public class Settlement
{
public string strike { get; set; }
public string type { get; set; }
public string open { get; set; }
public string high { get; set; }
public string low { get; set; }
public string last { get; set; }
public string change { get; set; }
public string settle { get; set; }
public string volume { get; set; }
public string openInterest { get; set; }
}
public class RootObject
{
public List<Settlement> settlements { get; set; }
public string updateTime { get; set; }
public string dsHeader { get; set; }
public string reportType { get; set; }
public string tradeDate { get; set; }
public bool empty { get; set; }
//## New added entries
public string instrumentName { get; set; }
public string contract { get; set; }
}
private static IEnumerable<Settlement> JsonFileToList(string directoryString, string fileString)
{
if (directoryString == null)
{
return null;
}
string path = directoryString + fileString + ".json";
if (!Directory.Exists(directoryString))
{
Directory.CreateDirectory(directoryString);
}
if (!File.Exists(path))
{
return null;
}
RootObject ro = JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(path));
var settlementList = ro.settlements;
foreach (var settlement in settlementList)
{
//## Do something with this data.
Console.Writeline(String.Format("Strike: {0}, Volume: {1}, Last: {2}", settlement.strike, settlement.volume, settlement.last));
}
return settlementList;
}

How to change the attribute display name when returning it as json in mvc?

I have a class
public class ProjectResultClass
{
public double F7 { set; get; }
}
in the controlller i fill it with data and want send it to page
[HttpPost]
public ActionResult CalculateProject(int Project)
{
ProjectResultClass Response= new ProjectResultClass();
Response.F7 = 123.4;
return Json(Response);
}
in the page a get F7: 123.4
I want to give the attribute another name for display.
better use it's to bring the name from resources file
something like
public class ProjectResultClass
{
[DisplayName = "MycustomResourceKey"]
public double F7 { set; get; }
}
try with this code
ProjectResultClass Response = new ProjectResultClass();
Response.F7 = 123.4;
return Json(new { MycustomResourceKey = Response.F7 });

Web Api 2 controller to download wikipedia api and show json output on web

I am trying to parse a wikipedia api which contain the short text of an article.I am using ASP.Net MVC for coding. My wikipedia api is https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exlimit=max&explaintext&exintro&titles=Berlin&redirects= which is in json formatted. At present what I have done is - inside the Model I created a folder named Wiki, and inside it I created four class named Limits.cs, Pageval.cs, Query.cs, Rootobject.cs.
public class Limits
{
public int extracts { get; set; }
}
public class Pageval
{
public int pageid { get; set; }
public int ns { get; set; }
public string title { get; set; }
public string extract { get; set; }
}
public class Query
{
public Dictionary<string, Pageval> pages { get; set; }
}
public class Rootobject
{
public string batchcomplete { get; set; }
public Query query { get; set; }
public Limits limits { get; set; }
}
Now in the controller class I created a WebApi 2 contrller to make the model object show on the web. In this case I am very new in handling this situation because I am new at MVC. I am trying to parse in this way but it is not working at all.
public class WikiController : ApiController
{
// GET: api/Wiki
// GET: api/Wiki/5
public string GetShortText(string name)
{
string result;
using (WebClient client = new WebClient())
{
var response = client.DownloadString("https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exlimit=max&explaintext&exintro&titles=" + name + "&redirects=");
var responseJson = JsonConvert.DeserializeObject<Rootobject>(response);
var firstKey = responseJson.query.pages.First().Key;
var extract = responseJson.query.pages[firstKey].extract;
try
{
Regex regex = new Regex(#".(?<=\()[^()]*(?=\)).(.)");
string.Format("Before:{0}", extract);
extract = regex.Replace(extract, string.Empty);
string result1 = String.Format(extract);
result = Regex.Replace(result1, #"\\n", " ");
}
catch (Exception)
{
result = "Error";
}
}
return result;
}
The Routconfig is-
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
You can do a couple of things. You can use attribute routing or you can define a route for your custom method. The reason it does not map at the moment is that you do not have a route that defines your parameter. So going the route way you can define
routes.MapRoute(
name: "Wiki",
url: "api/wiki/getshorttext/name",
defaults: new { controller = "Wiki", action = "GetShortText", name = UrlParameter.Optional }
)
;
On a side note as you are performing a I/O bound operation I would suggest making your action async using async and await feature of .net. This way you won't block any thread while you waiting for Wikipedia to respond. Also HttpClient offers a DownloadStringAsync which is awaitable. Have a look at async and await

get Facebook Pages in Windows Phone 7 using C# SDK

I tried to figure this out using the Windows Phone sample from the Facebook C# SDK page, but have been unsuccessful.
Here's the main code:
private void GetPages()
{
var fb = new FacebookClient(_accessToken);
fb.GetCompleted += (o, e) =>
{
if (e.Error != null)
{
Dispatcher.BeginInvoke(() => MessageBox.Show(e.Error.Message));
return;
}
var result = (IDictionary<string, object>)e.GetResultData();
// returns data and paging from Facebook
Dispatcher.BeginInvoke(() =>
{
foreach (var item in result)
{
// Not sure if/how to use the custom classes here
//item has .Key and .Value
//.Key = data and .Value contains the key/value pais for each of the pages returned
}
});
};
fb.GetAsync("me/accounts");
}
// Custom Classes
public class FacebookPageCollection
{
[JsonProperty(PropertyName = "data")]
public FacebookPage[] data { get; set; }
[JsonProperty(PropertyName = "paging")]
public FacebookPagePaging paging { get; set; }
}
public class FacebookPage
{
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "access_token")]
public string AccessToken { get; set; }
[JsonProperty(PropertyName = "category")]
public string Category { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
}
public class FacebookPagePaging
{
[JsonProperty(PropertyName = "previous")]
public Uri previous { get; set; }
[JsonProperty(PropertyName = "next")]
public Uri next { get; set; }
}
This is what the variable "result" returns:
{"data":[{"name":"value1","access_token":"value2","category":"value3","id":"value4","perms":["ADMINISTER","EDIT_PROFILE","CREATE_CONTENT","MODERATE_CONTENT","CREATE_ADS","BASIC_ADMIN"]},{"name":"value1","access_token":"value2","category":"value3","id":"value4","perms":["ADMINISTER","EDIT_PROFILE","CREATE_CONTENT","MODERATE_CONTENT","CREATE_ADS","BASIC_ADMIN"]}],"paging":{"next":"url"}}
What I'd like to do is retrieve and save details for each page.
I have been trying to figure this out and have looked over a number of other posts on here and elsewhere. I just don't have enough experience to figure it out.
Any help is appreciated.
Thank you.
Sri
Here is a trick to understanding how to work with json response in fb c# sdk.
Here is the mapping between Javascript JSON and C# JSON. (Notice there is no DateTime and another complex .net objects as it is not part of the JSON spec found in JSON.org)
JsonObject => keyvalue pairs => IDictionary<string, object> / IDictinary<string, dynamic>
JsonArray => array => IList<object> / IList<dynamic>
string => string
number => long/decimal
boolean => bool
Here is how you do the actual mapping.
var result = (IDictionary<string, object>)e.GetResultData();
var data = (IList<object>)result["data"];
foreach(var act in data) {
var account = (IDictionary<string,object>) act;
var name = (string)account["name"];
var accessToken = (string)account["access_token"];
var id = (string)account["id"];
// normalize to IList<string> permissions, so it is easier to work without casting.
var permissions = ((IList<object>)account["perms"]).Select(x => (string)x).ToList();
}