How to get single object from an api and display it [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am trying to build an app that helps you make dinner decisions. I want the user to be able to click a button and the app should display one random dinner name using an API. I am trying to display the data from an API. This is my code so far. I am getting a null exception. Any assistance is appreciated :)
namespace jello
{
public partial class NetworkingManager : ContentPage
{
private string name;
public string url;
public String Name {
get { return name; }
set
{
name = value;
}
}
public class RecipeClass
{
public class Data
{
public string strMeal { get; set; }
}
public Data data { get; set; }
}
public const string Url = "https://www.themealdb.com/api/json/v1/1/search.php?f=a";
public HttpClient client = new HttpClient();
public NetworkingManager()
{
InitializeComponent();
BindingContext = this;
name = GetDetails();
}
string temp;
public async void GetString()
{
var content = await client.GetStringAsync(Url);
temp = content;
}
public RecipeClass getObj()
{
var output = JsonConvert.DeserializeObject<RecipeClass>(temp);
return output;
}
public String GetDetails()
{
var name = getObj().data.strMeal;
return name;
}
}
}

Your underlying problem is that you want to call something asynchronous from your constructor and constructors cannot be async. You can solve that by using this asynchronous factory pattern:
First make your constructor private so it cannot be called from the outside:
private NetworkingManager()
{
InitializeComponent();
BindingContext = this;
}
Then you make an async method to initialize it:
private async Task<MyClass> InitializeAsync()
{
var temp = await GetStringAsync();
var output = JsonConvert.DeserializeObject<RecipeClass>(temp);
name = output.data.strMeal;
return this;
}
public async Task<string> GetStringAsync()
{
return await client.GetStringAsync(Url);
}
And finally an async method to create it:
public static Task<NetworkingManager> CreateAsync()
{
var manager = new NetworkingManager();
return manager.InitializeAsync();
}
You construct the instance from the outside by doing:
NetworkingManager instance = await NetworkingManager.CreateAsync();
And finally a note about naming: Don't call a class member temp. There's nothing temporary about it. It lives as long as the instance. Don't call a method the very general GetString if it gets a specific string like here. Call it GetMealString or GetMealName or something. The same goes for getObj, which should start with a capital letter by the way. Name your mebers in a clear and specific way and the program's structure will become much clearer to you.

You can do this :
public async void GetMeal()
{
var content = await client.GetStringAsync(Url);
var output = JsonConvert.DeserializeObject<RecipeClass>(content);
Name = output.data.strMeal;
}
And call it like this :GetMeal() you don't need to put name = GetMeal(); Your property
Name is set at the end.

Related

ASP.NET Web API possible deserialization issue while using flurl

I have a ASP.NET(C#, .NET 4.6.1) Web-Api-GET function which returns a complex object instance and is of generic type. Here is the return type definition (Note that the classes are much expansive in reality).
public class FileProcessInstance
{
public FileProcessInstance()
{ }
//ID that identifies file by primary key of log table
public int FileLogID;
//File name without path as received
public string OriginialFileName;
//Path with file name where file can be physically accessed
public string FileSharePath;
}
public class CommonStatusPayload<T> : CommonStatus
{
public CommonStatusPayload() : base(false)
{
Payload = default(T);
}
public CommonStatusPayload(T payload, bool status)
: base(status)
{
Payload = payload;
}
public virtual T Payload { get; private set; }
}
public class CommonStatus
{
public CommonStatus() : this(false)
{
}
public CommonStatus(bool status)
{
Status = status;
}
public bool Status { get; set; }
}
Now my web api looks like this:
[HttpGet]
public CommonStatusPayload<List<FileProcessInstance>> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>() { new FileProcessInstance() { FileLogID = 1, FileSharePath = #"\\d\s", OriginialFileName = "d.txt" } };
CommonStatusPayload<List<FileProcessInstance>> cs = new CommonStatusPayload<List<FileProcessInstance>>(lst, true);
return cs;
}
The issue is, a call to this api from C# code would receive null as payload, while Postman request does receive proper payload.
Now my client code looks like this:
static void Main(string[] args)
{
var lst = GetFilesForProcessing();
}
private static List<FileProcessInstance> GetFilesForProcessing()
{
List<FileProcessInstance> lst = new List<FileProcessInstance>();
try
{
Task<CommonStatusPayload<List<FileProcessInstance>>> task = GetFilesForProcessingFromAPI();
task.Wait();
if (task.Result.Payload != null)
lst.AddRange(task.Result.Payload);
}
catch (Exception ex)
{
}
return lst;
}
private static async Task<CommonStatusPayload<List<FileProcessInstance>>> GetFilesForProcessingFromAPI()
{
return await "http://localhost:10748/api/values/GetFilesForProcessing".ToString()
.GetAsync().ReceiveJson<CommonStatusPayload<List<FileProcessInstance>>>();
}
I have observed that the return payload works if it were to be a a) list by itslef b) a local instance of CommonStatusPayload<List<FileProcessInstance>>. This makes me believe that there is a possible deserialization issue, when the result is handed over to C# code from web-api. A fiddler check for the same request turns out to be just fine, just that C# client would not receive proper result.
Any guess as to what could be the underlying reason for payload being null?
I found the root cause of this issue. The private setter for Payload within CommonStatusPayload class is causing the deserialization to fail. Although for the intended behavior, i wanted the payload to be set only via constructor/method always to be associated with a relative status, at-least this change allows me to continue.
I did find some other questions here, related to JSON.NET with protected setters having same issues.

Xamarin sqlite-net-pcl accessing values of database internal

I'm using Visual Studio 2017, new to SQLite and can't get my head behind how I get to access the values saved in the database and get it back to the elements of the class.
public class MyObject
{
[PrimaryKey, AutoIncrement]
public int IndexNumber
{get;set;}
[MaxLength(20)]
public int SomeID
{get;set;}
[MaxLength(70)]
public string SomeName
{get; set;}
[MaxLength(25)]
public string Telephone
{get; set;}
public DateTime someTime
{get; set;}
//...some more data
}
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB (string dbPath);
database.CreateTableAsync<MyObject>().Wait();
public Task<List<MyObject>> GetMyObjectAsync()
{
return database.Table<MyObject>().ToListAsync();
}
public Task<MyObject> GetSingleObjectAsync(int ind)
{
return database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public Task<int> SaveMyObjectAsync(MyObject object)
{
if (object.IndexNumber == 0)
{
return database.InsertAsync(object)
}
else
{
return database.UpdateAsync(object);
}
}
public Task<int> DeleteMyObjectAsync(MyObject object)
{
return database.DeleteAsync(object);
}
}
Inputting data through the .xaml pages works without any problems so far, selecting the object in ListView works as well.
The problem now is that I just can't seem to find a proper way to convert the returned Task back to an object to update some of those values with data only supplied through a HTTP response which itself does not always supply all the data for the datatable, e.g. only the ID and a code if it was successful in the first response.
It then needs other data from the object and again delivers values for different elements of the object which is why I'd like to know if there was some method to get a row of data back to a temporary object to update it in the database, remove it if needed (canceled through the HTTP response) or modify it.
Your problem is all about not using await keyword. Whenever you call asynchronous method with no await keyword you are doing it wrong :) I strongly recommend you to read James Montemagno blog post about it here.
Here is solution of your problems.
public class MyDB
{
readonly SQLiteAsyncConnection database;
public MyDB(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
}
public async Task CreteMyDb()
{
await database.CreateTableAsync<MyObject>();
}
public async Task<List<MyObject>> GetMyObjectsAsync()
{
return await database.Table<MyObject>().ToListAsync();
}
public async Task<MyObject> GetSingleObjectAsync(int ind)
{
return await database.Table<MyObject>().Where(i => i.IndexNumber == ind).FirstOrDefaultAsync();
}
public async Task<int> SaveMyObjectAsync(MyObject myObject)
{
if (myObject.IndexNumber == 0)
{
return await database.InsertAsync(myObject);
}
else
{
return await database.UpdateAsync(myObject);
}
}
public async Task<int> DeleteMyObjectAsync(MyObject myObject)
{
return await database.DeleteAsync(myObject);
}
}
And example usage of methods.
await this.myDb.CreteMyDb();
await this.myDb.SaveMyObjectAsync(new MyObject()
{
SomeID = 1,
SomeName = "Adam",
someTime = DateTime.Now,
Telephone = "53535353"
});
var list = await this.myDb.GetMyObjectAsync();
Let me know if it helped!

Serializing Model using NewtonSoft in WPF Application

I am trying to serialize my model each second and push it to a server. I have set up a periodic task which executes each second. I call SendNewMessage to execute the push.
The first method call to SendNewMessage() which is called from the constructor runs fine with no exceptions or issues.
When the async task tries to call the SendNewMessage I get an exception and my application shuts down. It is the NewtonSoft code:
String PushModelToServer = JsonConvert.SerializeObject(this, jss); Which fails
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in
'C:\Users\snovva\Source\Workspaces\HMI\HMI.ViSoft\bin\x86\Debug\HMI.ViSoft.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x71041771, on thread 0x2788. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
public class Model : ModelBase
{
public Model ()
{
PeriodicTask.Run(() =>
{
SendNewMessage();
},
TimeSpan.FromSeconds(1));
SendNewMessage();
}
public void SendNewMessage()
{
// Send the message
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.Formatting = Newtonsoft.Json.Formatting.Indented;
String PushModelToServer = JsonConvert.SerializeObject(this, jss);
sendMessage(System.Text.Encoding.Unicode.GetBytes(PushModelToServer));
}
}
public class PeriodicTask
{
public static async Task Run(Action action, TimeSpan period, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await Task.Delay(period, cancellationToken);
if (!cancellationToken.IsCancellationRequested)
action();
}
}
public static Task Run(Action action, TimeSpan period)
{
return Run(action, period, CancellationToken.None);
}
}
More Info As requested:
The call on line 10 in the constructor runs. The serialization works the first time. Since the data in the model is changing I am pushing this model every second to update server. It is the async call which fails. As time passes the data in the model will change.
You can use [IgnoreDataMember] to avoid serializing properties that should not be included.
The code below works in my application, and should hopefully help you arrive at a solution for your app.
I am hoping that the code you show above is a snippet of your real code because there are some potential issues with the 1 second timer, re-entrancy, etc. Instead of doing this timer in the Model constructor, consider moving it to another function/class and setting up the timer/calls from an additional call you setup later...again, just some suggestions on arriving at a good pattern. Do more research here...
Here is how I get my data, what you want in your PushModelToServer:
public class BackupData
{
public List<Vehicles> Vehicles { get; private set; }
public List<FuelStops> FuelStops { get; private set; }
public BackupData(List<Vehicles> vehicles, List<FuelStops> fuelStops)
{
Vehicles = vehicles;
FuelStops = fuelStops;
}
public string ToJson(Formatting formatting = Formatting.None)
{
var json = JsonConvert.SerializeObject(this, formatting);
return json;
}
public static BackupData FromJson(string jsonBackupData)
{
var data = JsonConvert.DeserializeObject<BackupData>(jsonBackupData);
return data;
}
}
Here is a snippet of one of my classes:
[DebuggerDisplay("{VehicleName}")]
public class Vehicles : IComparable<Vehicles>, INotifyPropertyChanged
{
private string id;
public string Id
{
get { return id; }
set
{
if (id != value) { id = value; NotifyPropertyChanged(); }
}
}
private string vehicleName;
public string VehicleName
{
get { return vehicleName; }
set
{
if (vehicleName != value) { vehicleName = value; NotifyPropertyChanged(); }
}
}
public override string ToString()
{
return VehicleName;
}
[IgnoreDataMember]
public UpdateState UpdateState { get; set; }
....
And here is how I get the data so I can use it anywhere I want:
#if WINDOWS_PHONE_APP
private void OnExecuteBackup(SettingsPage obj)
{
#else
private async Task<bool> OnExecuteBackup(SettingsPage obj)
{
#endif
var backupData = App.JournalModel.GetBackupData().ToJson(Formatting.Indented);
...
await SaveBackupFile(file, backupData);
...
public class JournalModel
{
...
public BackupData GetBackupData()
{
var data = new BackupData(Vehicles.ToList(), FuelStops.ToList());
return data;
}
...
Good luck with your project.
Well there must be something the the class You're trying to serialize, that makes the serializer go crazy. Maybe instead of serializing 'this' You should try serializing an actual 'DataObject' - something that can be serialized, and doesn't contain references to Timers, tasks, ect.. ?

Implementing simple cache in Windows Phone 8.1 Class Library

I am trying to implement a simple caching mechanism in a windows phone 8.1 API that I am creating. I have chosen a Windows Phone Portable Class Library template in visual studio.
Refrence : http://channel9.msdn.com/Series/Windows-Phone-8-1-Development-for-Absolute-Beginners/Part-22-Storing-and-Retrieving-Serialized-Data
The cache class looks something like this,
[DataContract]
class cache
{
private const string JSONFILENAME = "data.json";
[DataMember]
Dictionary<Int32, item> cDictionary;
[DataMember]
int _maxSize;
public int MaxSize
{
get { return _maxSize; }
set { _maxSize = value; }
}
public cache(int maxSize){
cDictionary = new Dictionary<int, item>();
_maxSize = maxSize;
}
public void push(Int32 id, item obj)
{
if (!cDictionary.ContainsKey(id)) {
cDictionary.Add(id, obj);
}
}
internal static async Task<cache> Load()
{
cache obj = null;
try
{
var jsonSerializer = new DataContractJsonSerializer(typeof(cache));
using (var myStream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(JSONFILENAME))
{
obj = (cache)jsonSerializer.ReadObject(myStream);
}
}
catch (FileNotFoundException)
{
obj = null;
}
return obj;
}
internal static async void Save(cache obj)
{
var serializer = new DataContractJsonSerializer(typeof(cache));
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(
JSONFILENAME,
CreationCollisionOption.ReplaceExisting))
{
serializer.WriteObject(stream, obj);
}
}}
The item class whose objects go into the dictionary looks like this,
[DataContract]
class item
{
[DataMember]
string _fName;
public string FName
{
get { return _fName; }
set { _fName = value; }
}
[DataMember]
string _lName;
public string LName
{
get { return _lName; }
set { _lName = value; }
}
[DataMember]
int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
public item(int id, string fName, string lName)
{
this.Id = id;
this.FName = fName;
this.LName = lName;
}
}
The idea is : The end user creates an instance of the api and calls a method doSomething(). The method first looks in the cache (not shown in the example) if found, returns the Item object back, or else, gets the item object from a web service(not shown) and then push it to cache.
public class api
{
cache tCache;
string apiKey;
public laas(string apiKey)
{
this.apiKey = apiKey;
this.tCache = new cache(100);
}
public async void Initialize(api obj)
{
//If cache exists
obj.tCache = await cache.Load();
if (obj.tCache == null)
{
obj.tCache = new cache(100);
}
}
public void doSomething(string id)
{
tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx"));
cache.Save(tCache);
}
}
I wanted to initialize/load the cache in the constructor of the api class, but since ApplicationData.Current.LocalFolder provide only async methods to read and write data from persistent storage, I created a separate static async class Initiialize() that would load the cache, since making an async constructor makes no sense.
Problem: the statement tCache.push(id.GetHashCode(),new item(1,"xxxx","xxx")); in the doSomething() throws null reference exceptions. This could possibilly be happening because the tCache hasn't been loaded/initialized yet due to the async operation.
I had tried obj.tCache = await cache.Load().Result to wait for the loading to complete, but that hangs my application. (http://msdn.microsoft.com/en-us/magazine/jj991977.aspx)
Could you please point me in the right directions here? Is my diagnonis right? Is there a better way to do it? Any pointer is appreciated.
Thanks!
What is probably happening is that you're calling Initialize but not awaiting it, because it is async void.
What you need to do is change:
public async void Initialize(api obj)
To:
public async Task Initialize(api obj)
Then, you'll need to await Initialize(obj) which will ensure that caches completion before use.
Note that async void is ment only for top level event handlers and shouldn't be used otherwise.
Also, the reason Task.Result hangs your application is because it is causing a deadlock, which is related to the way async marshals your synchronization context between calls.

Design pattern for executing dependent methods in a class

I have a class in which I have to repeat multiple steps to complete a process like below, this is just a pseudo code to demonstrate what I am asking. Basically each method needs another method to do something, so a few methods are executed one after another to get the desired result, but somehow I don't like this, is there another way to achieve this may be using a design pattern? I have seen the chain of responsibility but that does not suit me as I don't have different type of processors.
Thanks
class Processor
{
void Process()
{
var credentials = GetCredentialsFromDb();
var result = ProcessData(credentials);
}
string GetCredentialsFromDb()
{
return "user";
}
string ProcessData(string credentials)
{
return ExtractData();
}
string ExtractData()
{
return ParseData();
}
string ParseData()
{
return ValidateData(data);
}
string ValidateData(string data)
{
return "validatedData";
}
}
As each of your method calls wraps around the subsequent one, I'd say that the decorator pattern could fit your needs.
This would allow you to specify how the stack is build by only accepting certain types to be wrapped in others, if this is important.
You probably want a Builder Pattern - http://en.wikipedia.org/wiki/Builder_pattern
Basically the builder initializes your object and contains all of the logic, each in separate methods taking arguments for what information they need, for "building up" the end result.
Then you would implement a director that always calls them in sequence.
public static void main() {
var builder = new ProcessorBuilder();
ProcessorDirector director = new ProcessorDirector();
director.Build();
Console.WriteLine(builder.Processor);
}
class ProcessorDirector { //I tell processor builders how to build processors!
ProcessorBuilder _builder {get;private set;}
public ProcessorDirector(ProcessorBuilder builder) {
_builder = builder;
}
public void Build() {
var credentials = _builder.GetCredentialsFromDB();
var data = _builder.ProcessData(credentials);
var isDataValid = _builder.ValidateData();
if(isDataValid) {
_builder.ParseData();
}
}
}
class ProcessorBuilder
{
public string Processor {get;set;}
void ProcessorBuilder()
{
//if you change your end result object into a non-value type, you'd initialize it here.
}
public string GetCredentialsFromDb()
{
return "user";
}
string ProcessData(string credentials)
{
//process
//builder should be stateless, so return data
}
public string ParseData()
{
//parse
}
public string ValidateData()
{
//validate
}
}

Categories