Firebase Realtime Database Retrieved Single Data on Xamarin Android - c#

I successfully get the data from realtime database firebase when I put break point on OndataChange but when I put the break point after the OnDataChange method the records are now null.
public void OnDataChange(DataSnapshot dataSnapshot)
{
if (dataSnapshot.Value != null)
{
reclist.Clear();
TempDB rec = new TempDB();
rec.ID = dataSnapshot.Key;
rec.Firstname = dataSnapshot.Child("FirstName").Value.ToString();
rec.Lastname = dataSnapshot.Child("LastName").Value.ToString();
rec.Address = dataSnapshot.Child("Address").Value.ToString();
rec.ContactNo = dataSnapshot.Child("Contact number").Value.ToString();
rec.Email = dataSnapshot.Child("EmailAddress").Value.ToString();
rec.Password = dataSnapshot.Child("Password").Value.ToString();
idd = rec.ID;
Console.WriteLine(id.ToString());
reclist.Add(rec);
}
}

That's because data is loaded from Firebase asynchronously, while the rest of your code continues. Then once the data is loaded, your onDataChange is called with it. This means that the code just after what you shared indeed runs before the code inside the onDataChange, and that is working as intended.
The solution is always the same: any code that needs the data from the database needs to be inside onDataChange, be called from there, or be otherwise synchronized.
Have a look at these two (Android) examples for some ideas:
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener

Related

Nopcommerce Update entity issue

Using NopCommerce 3.8, Visual Studio 2015 proff.
I have created a plugin that is responsible for making restful calls to my Web API that exposes a different DB to that of Nop.
The process is run via a nop Task, it successfully pulls the data back and i can step through and manipulate as i see fit, no issues so far.
Issue comes when i try to update a record on the product table, i perform the update... but nothing happens no change, no error.
I believe this is due to the Context having no idea about my newly instantiated product object, however I'm drawing a blank on what i need to do in relation to my particular example.
Similar questions usually reference a "model" object that is part of the parameter of the method call, "model" has the method ToEntity which seems to be the answer in similar question in stack.
However my example doesn't have the ToEntity class/method possibly because my parameter is actually a list of products. To Clarify here my code.
Method in RestClient.cs
public async Task<List<T>> GetAsync()
{
try
{
var httpClient = new HttpClient();
var json = await httpClient.GetStringAsync(ApiControllerURL);
var taskModels = JsonConvert.DeserializeObject<List<T>>(json);
return taskModels;
}
catch (Exception e)
{
return null;
}
}
Method in my Service Class
public async Task<List<MWProduct>> GetProductsAsync()
{
RestClient<MWProduct> restClient = new RestClient<MWProduct>(ApiConst.Products);
var productsList = await restClient.GetAsync();
InsertSyncProd(productsList.Select(x => x).ToList());
return productsList;
}
private void InsertSyncProd(List<MWProduct> inserted)
{
var model = inserted.Select(x =>
{
switch (x.AD_Action)
{
case "I":
//_productService.InsertProduct(row);
break;
case "U":
UpdateSyncProd(inserted);
.....
Then the method to bind and update
private void UpdateSyncProd(List<MWProduct> inserted)
{
var me = inserted.Select(x =>
{
var productEnt = _productRepos.Table.FirstOrDefault(ent => ent.Sku == x.Sku.ToString());
if(productEnt != null)
{
productEnt.Sku = x.Sku.ToString();
productEnt.ShortDescription = x.ShortDescription;
productEnt.FullDescription = x.FullDescription;
productEnt.Name = x.Name;
productEnt.Height = x.Pd_height != null ? Convert.ToDecimal(x.Pd_height) : 0;
productEnt.Width = x.Pd_width != null ? Convert.ToDecimal(x.Pd_width) : 0;
productEnt.Length = x.Pd_depth != null ? Convert.ToDecimal(x.Pd_depth) : 0;
productEnt.UpdatedOnUtc = DateTime.UtcNow;
}
//TODO: set to entity so context nows and can update
_productService.UpdateProduct(productEnt);
return productEnt;
});
}
So as you can see, I get the data and pass data through to certain method based on a result. From that list in the method I iterate over, and pull the the entity from the table, then update via the product service using that manipulated entity.
So what am I missing here, I'm sure its 1 step, and i think it may be either be because 1) The context still has no idea about the entity in question, or 2) Its Incorrect calls.
Summary
Update is not updating, possibly due to context having no knowledge OR my methodology is wrong. (probably both).
UPDATE:
I added some logger.inertlog all around my service, it runs through fine, all to the point of the call of update. But again I check the product and nothing has changed in the admin section.
plugin
I have provided the full source as i think maybe this has something to do with the rest of the code setup possibly?
UPDATE:
Added the following for testin on my execute method.
var myprod = _productRepos.GetById(4852);
myprod.ShortDescription = "db test";
productRepos.Update(myprod);
This successfully updates the product description. I moved my methods from my service into the task class but still no luck. The more i look at it the more im thinking that my async is killing off the db context somehow.
Turned of async and bound the getbyid to a new product, also removed the lambda for the switch and changed it to a foreach loop. Seems to finally update the results.
Cannot confirm if async is the culprit, currently the web api seems to be returning the same result even though the data has changed (some wierd caching by deafult in .net core? ) so im creating a new question for that.
UPDATE: It appears that the issue stems from poor debugging of async. Each instance I am trying to iterate over an await call, simply put im trying to iterate over a collection that technically may or may not be completed yet. And probably due to poor debugging, I was not aware.
So answer await your collection Then iterate after.

Holding Values in an object for console application C#

I am currently writing an application where I am getting data from the DB and passing it to the object which will later be used to send the data off else where. The issue I am having in testing is that the data doesn't hold in the object as when it is used later, I get null value errors. I know we can store these in sessions, but I also know you can use objects and have done it before at previous jobs, but do not recall what I am missing to maintain the information. Would I need to pass the object(s) from method to method until the job is done?
the first sample here shows where it is prepping the object.
public void FtpInitialize()
{
_LogController.LogToFile(ValidateMessage.BeginInitialization);
//Loading FTPClient object with ClientInfo Object data we got from DataBase. FTPClient object is the object that sends the data.
_LogController.FTPTraceLogToFile();
ClientInfo = _RepositoryController.GetClientInfo(ClientInfo);
if (ClientInfo == null)
ClientInfo.ClientDataExists = false;
else
{
FTPClient.Host = ClientInfo.Host;
FTPClient.Port = ClientInfo.Port;
FTPClient.EncryptionMode = FtpEncryptionMode.Explicit;
FTPClient.Credentials = new NetworkCredential(ClientInfo.UserName, ClientInfo.Password);
FTPClient.DataConnectionType = FtpDataConnectionType.EPSV; //according library documentation, auto passive is broken as of 10/20/2016
FTPClient.EnableThreadSafeDataConnections = ClientInfo.EnableThreadSafeConnection;
FTPClient.DataConnectionConnectTimeout = ClientInfo.DataConnectionTimeout;
FTPClient.DataConnectionReadTimeout = ClientInfo.DataReadTimeout;
FTPClient.ConnectTimeout = ClientInfo.ConnectionTimeout;
FTPClient.ReadTimeout = ClientInfo.ReadTimeout;
FTPClient.SocketPollInterval = ClientInfo.SocketPollInterval;
FTPClient.SocketKeepAlive = ClientInfo.KeepSocketAlive;
FTPClient.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
_LogController.LogToFile(ValidateMessage.ClientDataLoaded);
ClientInfo.ClientDataExists = true;
}
}
then below when I hit this part, it shows as null
public bool SendData()
{
short errorCount = 0;
using (FTPClient)
{
if (ClientInfo.ClientDataExists)
{
This looks like you are using local variables in your methods. This is why the data "disappears".
For example if you are pulling data from your database you should have some kind of model class and container so that the data can persist until you are done with it.
EX: You have a database that contains information on people (name, dob, etc).
You should have a class that defines person and possibly a List to store said people. You call your database and pull X person objects into your List variable. You then can pass your List into the methods. Note: You can ditch the List (or whatever collection you use) if you are doing it one at a time.
The implementation of this really depends on how you want the objects to persist. If you know you will only pull one person object at a time you can declare var databasePerson from the database. Use the List if you will be pulling more information and then pop off the object when your are down with it.
Hope that helps.

Trouble inserting into Azure db from Windows Store app

I'm currently working on a Windows Store app (for a school assignment), and I'm having trouble inserting data into my database which is stored in Azure. Whenever I attempt to insert data into the db, the MobileServiceInvalidOperationException gets thrown. My code is as follows:
In my model class
class Division
{
public string Id {get; set;}
[JsonProperty(PropertyName = "divisionTitle")]
public string DivisionTitle {get; set;}
}
And the relevant code in my MainPage.xaml.cs file
private MobileServiceCollection<Division, Division> divisionItems;
private IMobileServiceTable<Division> divisionTable = App.MobileService.GetTable<Division>();
private async void InsertDivision(Division divisionItem)
{
// This code inserts a new division Item into the database.
// When the operation completes and Mobile Services has
// assigned an Id, the item is added to the collection
try
{
await divisionTable.InsertAsync(divisionItem);
divisionItems.Add(divisionItem);
}
/////////////////////////////////////////////////////////
// The MessageDialog that pops up when this exception //
// gets thrown is: //
// //
// Internal Server Error (HTTP 500) //
////////////////////////////////////////////////////////
catch (MobileServiceInvalidOperationException e)
{
MessageDialog errormsg = new MessageDialog(e.Message,
string.Format("{0} (HTTP {1})",
e.Response.ReasonPhrase,
(int)e.Response.StatusCode));
var ignoreAsyncOpResult = errormsg.ShowAsync();
}
}
private void DivisionButtonSave_Click(object sender, RoutedEventArgs e)
{
var DivisionItem = new Division
{
DivisionTitle = DivisionInput.Text
};
InsertDivision(DivisionItem);
}
I also added a script in the management portal:
function insert(item, user, request) {
if (item.DivisionTitle.length > 15) {
request.respond(statusCodes.BAD_REQUEST, 'Division title must be under 15 characters');
}
else {
request.execute();
}
}
Before making the changes above, I was having no trouble communicating with Azure from within the app and wasn't having any problems inserting data. It's only after editing the script in Azure (the default insert method is simply the request.execute() statement), and since I added the InsertDivision method (I was previously entering data into the db directly from the event handler with the command await App.MobileService.GetTable<Division>().InsertAsync(DivisionItem);) that this problem has started to occur. I've tried a couple of different things and nothing has worked. After looking at my code does anything stick out? Thanks in advance to anyone who can help.
In the request sent to the service, the property DivisionTitle is sent with the first letter in lower case (since you defined it as such with the JsonProperty attribute):
{"divisionTitle":"the actual title"}
On your script, you're trying to access the property item.DivisionTitle (which doesn't exist, JavaScript is case-sensitive), and then access a property (length) of this undefined value. That will cause an error in your script. If you either change the script to use the actual JSON name (item.divisionTitle.length > 15) or change the JsonProperty declaration in the client to send the property with the first letter in upper case, it should work.
By the way, if you go to the "logs" tab in the portal, you should see some error which explains why you're getting the internal server error.

Storing global variables in c#?

I basically have created a class which when a user logs into a website it then queries the database and stores some settings in a List (So I have key/pair values).
The reason for this is because I want to always be able to access these settings without going to the database again.
I put these in a class and loop through the fields via a SQL query and add them to the list.
How can I then access these variables from another part of the application? or is there a better way to do this? I'm talking server side and not really client side.
Here is an example of what I had at the moment:
public static void createSystemMetaData()
{
string constring = ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
SqlConnection sql = new SqlConnection(constring);
sql.Open();
SqlCommand systemMetaData = new SqlCommand("SELECT * FROM SD_TABLES", sql);
//Set Modules
using (SqlDataReader systemMetaDataReader = systemMetaData.ExecuteReader())
{
while (systemMetaDataReader.Read())
{
var name = systemMetaDataReader.GetOrdinal("Sequence").ToString();
var value = systemMetaDataReader.GetOrdinal("Property").ToString();
var Modules = new List<KeyValuePair<string, string>>();
Modules.Add(new KeyValuePair<string, string>(name, value));
}
}
}
Thanks
Any static properties of a class will be preserved for the lifetime of the application pool, assuming you're using ASP.NET under IIS.
So a very simple class might look like:
public static class MyConfigClass
{
public static Lazy<Something> MyConfig = new Lazy<Something>(() => GetSomethings());
public static Something GetSomethings()
{
// this will only be called once in your web application
}
}
You can then consume this by simply calling
MyConfigClass.MyConfig.Value
For less users you can go with the SessionState as Bob suggested,however with more users you might need to move to a state server or load it from Data Base each time.
As others have pointed out, the risk of holding these values in global memory is that the values might change. Also, global variables are a bad design decision as you can end up with various parts of your application reading and writing to these values, which makes debugging problems harder than it need be.
A commonly adopted solution is to wrap your database access inside a facade class. This class can then cache the values if you wish to avoid hitting the database for each request. In addition, as changes are routed through the facade too, it knows when the data has changed and can empty its cache (forcing a database re-read) when this occurs. As an added bonus, it becomes possible to mock the facade in order to test code without touching the database (database access is notoriously difficult to unit test).
From the looks of things you are using universal values irrespective of users so an SqlCacheDependency would be useful here:
Make sure you setup a database dependency in web.config for the name Test
public static class CacheData {
public static List<KeyValuePair<string,string>> GetData() {
var cache = System.Web.HttpContext.Current.Cache;
SqlCacheDependency SqlDep = null;
var modules = Cache["Modules"] as List<KeyValuePair<string,string>>;
if (modules == null) {
// Because of possible exceptions thrown when this
// code runs, use Try...Catch...Finally syntax.
try {
// Instantiate SqlDep using the SqlCacheDependency constructor.
SqlDep = new SqlCacheDependency("Test", "SD_TABLES");
}
// Handle the DatabaseNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableNotifications method.
catch (DatabaseNotEnabledForNotificationException exDBDis) {
SqlCacheDependencyAdmin.EnableNotifications("Test");
}
// Handle the TableNotEnabledForNotificationException with
// a call to the SqlCacheDependencyAdmin.EnableTableForNotifications method.
catch (TableNotEnabledForNotificationException exTabDis) {
SqlCacheDependencyAdmin.EnableTableForNotifications("Test", "SD_TABLES");
}
finally {
// Assign a value to modules here before calling the next line
Cache.Insert("Modules", modules, SqlDep);
}
}
return modules;
}

Implementing queue in c#

I am developing a c# application, in which the server gets requests from many clients at a time. Each client also gets their data from different databases. In this situation sometimes data leakage is happening, means clients get data from an incorrect database. Say for example client1 should get data from db1 and client2 gets data from db2. Instead they get data from opposite databases; client1 gets from db2 and client2 gets from db1.
I am adding the code below where it collects the data.
public string List()
{
Response.ContentType = ContentType.Xml;
try
{
ThingzFilter filter = null;
Dictionary<string, string> parameters = new Dictionary<string, string>();
if (Id!="")
{
// get parameters from http request
foreach (HttpInputItem param in Request.Param)
parameters.Add(param.Name, param.Value);
setServerURLs();
//Request.Clear();
if (Request.QueryString["lang"].Value != null)
{
ThingzDB.TzThing.get_language = Request.QueryString["lang"].Value.ToString();
}
else
{
ThingzDB.TzThing.get_language = SessionDatabase.DefaultLanguage;
}
}
ThingzDatabase db = SessionDatabase;
langStr = db.Language;
// this is run if there was no ID supplied
// which means we want all items of all types
if (Id == "")
{
if (Request.AcceptTypes == null)
{
//TypeController.session_id = Request.QueryString["sessionid"].Value;
jobs.Add(Request.QueryString["sessionid"].Value);
if (nextJobPos > jobs.Count - 1)
return "";
else
{
TypeController.session_id = jobs[nextJobPos];
nextJobPos++;
langStr = SessionDatabase.Language;
}
filter = new AllThingzFilter(SessionDatabase, parameters, langStr);
TypeController.session_id = "";
filter.Execute();
}
In this server is console application and clients are windows where the site names , means the databse names are mentioned.
Please give me a solution to overcome this issue.
Without precisely knowing how SessionDatabase is scoped (from the name it seems to be a session variable) or whether it's implementation is a property that does some kind of complex logic, I would guess you have two problems:
Storing the value at the wrong scope with multiple clients accessing it
Using db and SessionDatabase interchangeably in your code.
For the latter, I would suggest db = SessionDatabase once at the top of the code (making sure that SessionDatabase was the right thing for that client, and then using db for the rest of the method.

Categories