I'm using Firebase Realtime Database to store a list of users and their friends for a game. Saving data has given me no problems but retrieving it has been giving me problems for a couple of days now. Whenever I retrieve data and call any Unity function (I've tested a PlayerPrefs.GetString() and Instantiate()), the program stops, without any error, but also lets me do other things because it's asynchronous (better explained by code below).
I've tried running it through a debugger and using a bunch of print statements to see what the problem is. However, the program doesn't give me any error so it's been impossible to debug it. I've just been guessing blindly.
I've managed to recreate the problem in the simplest way here:
using Firebase;
using Firebase.Database;
using Firebase.Unity.Editor;
using UnityEngine;
public class FirebaseData : MonoBehaviour {
private void Awake() {
PlayerPrefs.SetString("test", "hello");
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("HERE IS THE URL TO MY PROJECT");
TestRetrieve();
}
public void TestRetrieve() {
FirebaseDatabase.DefaultInstance.GetReference("users/").GetValueAsync().ContinueWith(task => {
if (task.IsFaulted) {
// Handle the error...
} else if (task.IsCompleted) {
DataSnapshot snapshot = task.Result;
print("here");
PlayerPrefs.GetString("test");
print("there");
}
});
}
}
You would expect the program to print "here" and then print "there". However, only "here" gets printed and then whatever code follows the "PlayerPrefs.GetString("test);" line will not ever be run. There is no errors given.
This is literally the only script in the project, just attached to an empty GameObject.
The weird part is that the print functions and most other ones not related to Unity but just pure c#, seem to be working. It's only the Unity functions which are giving me trouble.
Use async event handlers to allow for a better syntax flow.
public class FirebaseData : MonoBehaviour {
void Start() {
PlayerPrefs.SetString("test", "hello");
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("HERE IS THE URL TO MY PROJECT");
TestRetrieve();
}
public void TestRetrieve() {
retrieve += onRetrieve;
retrieve(this, EventArgs.Empty);
}
event EventHandler retrieve = delegate { };
private async void onRetrieve(object sender, EventArgs args) {
retrieve -= onRetrieve;
try {
DataSnapshot snapshot = await FirebaseDatabase.DefaultInstance.GetReference("users/").GetValueAsync();
print("here");
PlayerPrefs.GetString("test");
print("there");
} catch (Exception ex) {
// Handle the error here...
}
}
}
Reference Async/Await - Best Practices in Asynchronous Programming
Related
I have some recursive code in my windows10 App (UWP platform)
I know that there are no direct way to catch StackOverflowException on C#, but there is a way by using Thread class on Windows Forms API. And I can't apply solution to UWP, because there are no Thread class.
So, I have some code and I need to try execute it and stop it's Thread if it's fails.
I also want to detect exception if it's possible.
User can be satisfied by half finished work.
My application is closing if recursion is too big.
How to fix someWork(byte[] data) method?
public sealed partial class MainPage : Page {
private byte[] dataArray; // value is creating by user
// data can be very big, so not-resursive code can use all App's memory and crush it too!!
private async void ButtonClick(object sender, RoutedEventArgs ev) { // here I run method
bool isFinished = someWork(dataArray);
// then I show dataArray (no matter finished or not) to user
}
private static bool someWork(byte[] data) { // I need to fix this method
int start_arg = 0;
try {
someWork_recursive(data, start_arg);
return true; // All done
} catch (Exception) { } // I trying to catch StackOverflowException here
return false; // Half-finished
}
private static void someWork_recursive(byte[] data, int arg) { // My question is NOT about body of this method
// code that run someWork_recursive() again or not
// also code that change data[] values
}
}
I have used MouseKeyboardActivityMonitor to set some limitations for user activities for example disable mouse.
www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
I have these code in my form
public partial class MyForm:Form
{
KeyboardHookListener kl;
MouseHookListener ml;
MyForm:Form()
{
ml = new MouseHookListener( new GlobalHooker());
ml.Enabled=true;
}
private void MyForm_Load
{
ml.MouseDownExt += ml_MouseDownExt;
// And same thing for Click or ...
}
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
// I have got hard disk serial number here
string sn = HardDisk.Serial;
}
}
And code of HardDisk.Serial
ManagementObjectSearcher s= new ManagementObjectSearcher(" SELECT *...");
foreach( var wmi in s.Get())
{
}
I get error when I click on MyForm .
When I built my solution and run it manually
I get this error
The application called an interface that was Marshalled for different thread
Stack:
at system.management.MangementException.ThrowWithExtendedInfo( Exception e)
at system.management.MangementObjectSearcher.Get()
at HardDisk.Get_serial()
at ml_MouseDownExt( object sender,MouseEventExtArgs e)
at MouseKeyboardActivityMonitor.MouseHookListener.InvokeMouseEventHandlerExt(EventHandler'1 handler,MouseEventExtArgs e)
But when I run my solution with visual studio an exception will throw at HardDisk.serial
at s.Get line , I get this
Error:
Managed debugging assistant ' DisconnectedContext'
Has detected a problem in 'my app Name.exe'
Transition into com context 0xa4206 for this runtime callable wrapper failed with following error :
an outgoing call can't be made since the application is dispatching an input asynchronous call
It obvious that two error is from MangementObjectSearcher class.I get serial number in another place in MyForm .errors just occurres when get serial in ml_MouseDownExt method or other method that has been added to events of GlobalHooker .I have seen msdn. In inheritance hierarchy of MangementObjectSearcher I see System.MarshalByRefObject
https://msdn.microsoft.com/en-us/library/system.management.managementobjectsearcher(v=vs.110).aspx
I don't know that it is related to these errors or not
How should I avoid these errors?
Your hook callback isn't being raised on the right thread. And that's just the first problem. Wrap it in a BeginInvoke and all will be well:
private void ml_MouseDownExt( object sender,MouseEventExtArgs e)
{
e.Handled= true;
var wrongThread = new Action(()=>
{
// I have got hard disk serial number here
string sn = HardDisk.Serial;
//put anything else you were planning on doing with sn here
}
BeginInvoke(wrongThread, null);
}
The second problem is that you're trying to interact with a COM object in the handler for a global hook. BeginInvoke should get around that nicely by delaying it for a few microseconds.
Don't forget to make sure Dispose gets called on that global hook. Closing the app isn't enough unless you like rebooting often.
The application takes a lot of database queries. Request is created after the event made by the user or through the use of several timer (10 sec tick).
The problem occurs when the database server suddenly becomes unavailable. This causes a huge amount of on-screen messages containing information about the error in the connection.
I would like to achieve a situation in which a failed open call will freeze the application and open a single window that indicates a problem where the connection attempt will be retried every X seconds (plus a progress bar). If the connection is restored window is closed and the application will unlock.
How to do it? Please assumptions / guidelines or examples of ready-made solutions.
So if I understand you right, it's a usability problem. Your goal is for your users to be happy & confident that all is well, whilst waiting for a db connection. You don't want: panicky users pressing random buttons, phoning for help and complaining. You don't want a load of meaningless technical error messages; nor a frozen app with no messages. But you will accept a temporarily frozen app with a good helpful message.
Good usability doesn't come cheap. If you want to allow the user to cancel, then you have to learn some multi-threading. For that, I'd start here: http://msdn.microsoft.com/en-us/library/ms951089.aspx. You can avoid this if you are satisfied with a static message saying 'please wait, database connection may take up to xxx seconds...'.
I take a wild guess that your WinForms app calls the database from lots of places, but you'd like something that doesn't take days of re-writing.
The simplest single-threaded solution I can think of is to define a PleaseWaitForm and a 'wrapper' method, which I'll call DoWithPleaseWait(), which will go round all your business logic/data access calls, showing and hiding the please wait form:
namespace WinFormsPleaseWaitExample
{
//You don't need these 2 lines if you have .Net 3 or later
public delegate void Action();
public delegate TResult Func<TResult>();
//
public partial class Form1 : Form
{
private readonly Form pleaseWaitForm;
public Form1()
{
InitializeComponent();
pleaseWaitForm = new PleaseWaitForm {Owner = this};
}
private void button1_Click(object sender, EventArgs e)
{
var result= DoWithPleaseWait(delegate { return SomeBusinessLayerClass.ADataRetrieval("boo"); });
MessageBox.Show(result.ToString());
}
private void button2_Click(object sender, EventArgs e)
{
DoWithPleaseWait(delegate { SomeBusinessLayerClass.ADataOperation("boo"); });
}
public void DoWithPleaseWait(Action action)
{
pleaseWaitForm.Show();
action.DynamicInvoke();
pleaseWaitForm.Hide();
}
public TResult DoWithPleaseWait<TResult>(Func<TResult> func)
{
pleaseWaitForm.Show();
TResult result = (TResult)func.DynamicInvoke();
pleaseWaitForm.Hide();
return result;
}
}
public class SomeBusinessLayerClass
{
public static void ADataOperation(string someInput)
{
//Do something that might take several seconds...
Thread.Sleep(3000);
}
public static object ADataRetrieval(string someInput)
{
//Do something that might take several seconds...
Thread.Sleep(3000);
return someInput + " returned";
}
}
}
I'm trying to optimize my code to be called from both an UI-less commandline call or call it from the UI.
The problem is that I have is I have written the lets call It worker-code inside the Form-class.
Now I want to pull out that worker code into a separate class.
Lets make a small sample to make my needs clearer:
public partial class form1 :Form
{
void AddLogmessage(String msg)
{
// update an listview
ListViewItem item = new ListViewItem();
item.Text = msg;
// Add the item to the ListView
LogView.Items.Add(item);
}
// button on ui to start working
private void btnStartTestRun_Click(object sender, EventArgs e)
{
try
{
DoSomeWork();
}
catch(Exception ex)
{}
}
private void DoSomeWork()
{
// do some really generic hard work....
AddLogMessage("working");
// do some more generic long lasting hard work....
AddLogMessage("working goes on...");
// in case of an error throw Exception
}
Now I want to refcator the worker code to work outside the form class, but be able to report the things that happen to the UI (if there is one) or to call the workercode without UI and do other reportings to an different target (communicate with other library which reports the results to an server)
Something like this:
public void AutomaticTaskHandler()
{
string[] cmdline = Environment.GetCommandLineArgs();
Arguments args = new Arguments(cmdline);
if (args["automatic"] != null)
{
doSomeWork();
}
}
In this case I don't have to report the Messages to the UI, but send some other messages (NOT the same Messages!!) to an server.
So my question is how do I make this the best way not having to write the doSomeWork - code twice but be able to send only the messages which are in the current scene are needed?
I thought about Delegates and Events, but I'm not too familiar to this to make this work.
Any help will be appreciated.
Thanks Meister_Schnitzel
Basically, you would create an interface IMessageTarget with a method SendMessage. Your UI code would create an implementation of that interface that outputs the messages to the UI and your console code would create an implementation of that interface that sends the messages to a server. On calling the doWork method, you would supply an instance of IMessageTarget.
Hello yeah I'm asking this question a second time, sorry about that but I don't know how to bump previous question. I'll explain more in depth my problem in a more completed example.
Instead of writing like 300+ Event classes in 300 class files which I may have to do if this doesn't work, so they can do little timed jobs like this example job below in a server project.
What i'm trying to avoid is writing a bunch of classes and simply just write everything more compacted in structure of whatever i'm working on.
To sum it up, i'm mixing 90% functional programming and want to give some function some delayed timed event, without creating the new timed event in a separate class then running back and forth through the files looking how everything is linked up, but this way everything can be seen so you can find bugs and whatnot much faster as everything is right in front of you, kinda like writing loop code, but with delay.
All I have right now is one thread which processes events, deletes events which have been stopped, keeps re-running events which don't stop after one cycle and of course waiting until some events can be ran.
If anyone knows a better way to do what i'm trying to do maybe some built-in C# Event system? Which is preferably simple.
class Event {
private Action action;
private bool stopped;
public Event(long tick, Action action) {
this.tick = tick;
this.action = action;
this.lastRun = Environment.TickCount;
}
public void stop() {
stopped = true;
}
public bool canRun() { //blah ignore just showing what I plan to do
if (stopped)
return false;
return (Environment.TickCount - lastRun) > tick;
}
public void run() {
this.lastRun = Environment.TickCount;
action();
}
//... other methods
}
class Test {
string t;
public void setT(string t) {
this.t = t;
}
public void stuff() {
Console.WriteLine(a);
}
}
class ImportantWork {
public static void Main(string[] args) {
someDeepMethod();
}
void someDeepMethod() {
Test t = new Test();
t.setT("secondTime");
//Here is where the problem occurs.
Server.registerEvent(new Event(5000, () => {
this.stop(); //<-- Error how I call this from this new Event instance.
stop(); //<-- Also error
//Event.stop(); //<-- haha may work if it was static but thats stupid
t.stuff();
Console.WriteLine("thirdTime");
}));
t.setT("firstTime");
t.stuff();
}
}
Expected output:
firstTime
...waits 5 seconds...
secondTime
thirdTime
I don't know how you'd be able to do that inline like that. Why can't you use some kind of set-function and make it two lines?
MyEvent newEvent;
Server.registerEvent((newEvent = new MyEvent(5000)));
newEvent.setAction(() => {
newEvent.stop();
t.stuff();
Console.WriteLine("thirdTime");
});
It seems to me like there's some kind of structural issue with your design. I'm assuming that the example you provided was not actually what you were working with, just a simple example to address the problem you're having. If it is, however, the example you're working with why don't you just add a boolean flag in the constructor to tell the instance whether or not to call this.stop() on itself - instead of requiring it specified in the Action?
Best of luck!