1

My application sends the users credentials to the server, if they are correct the server send a packet telling the client their credentials are wrong or right. After a couple of dummy tests, my client crashed due to this line of code;

            var count = await reader.LoadAsync(512);

Debugging shows that the count is 0,

But before crashing, I was able to send seven (7) dummy requests to the server. And the client was able to read seven (7) of the replies.

    private async void loginButtonEvent(object sender, RoutedEventArgs e)
    {
        //disable the button so the user can't spam the login button and flood packets 
        loginButton.IsEnabled = false;

        //if the user is connected to the server, then allow
        if(connected)
        {
            //get the stream
            DataWriter writer = new DataWriter(clientSocket.OutputStream);

            //custom class (like a packet IO, messafe frame/ framing
            MessageData md = new MessageData();
            md.MyUser = new User(usernameTextBox.Text, passwordTextBox.Text);
            md.MyType = MessageData.mType.LOGINREQUEST;
            //Serialize it into a string, thank you newton.Json
            string output = JsonConvert.SerializeObject(md);
            //write to the server
            writer.WriteString(output);
            //dedicate and push
            await writer.StoreAsync();
            //flush like you flush a toilet so it doesn't get clogged in the pipeline
            await writer.FlushAsync();
            //detatch the stream, not sure why?
            writer.DetachStream();

            //get the input stream
            DataReader reader = new DataReader(clientSocket.InputStream);
            //create string to hold the data
            string receivedData;
            //dynamically process the data
            reader.InputStreamOptions = InputStreamOptions.Partial;
            //store the bytes in count? why do we pass 512? What if I send a picture to the server and it is 1mb?
            var count = await reader.LoadAsync(512);
            //covert the byte to a string
            receivedData = reader.ReadString(count);
            //construct the md object into what the server sent
            md = JsonConvert.DeserializeObject<MessageData>(receivedData);
            switch (md.MyType)
            {
                case MessageData.mType.LOGINFAILED:
                    messageBox("Username or Password is wrong");
                    //Todo://
                    break;
                case MessageData.mType.LOGINSUCCESS:
                    messageBox("Logged");
                    //TODO: Go to login screen
                    break;
            }

            await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(1));


        }
        loginButton.IsEnabled = true;


    }

I tested this once more, and this time I was able to send twelve (12) packets to the server, and receive tweleve (12) packets that the client was able to intpretate.

Once again, the error lies in

            var count = await reader.LoadAsync(512);

An exception of type 'System.ObjectDisposedException' occurred in MobileApp.exe but was not handled in user code

Object Disposable Exception was unhanded by user code.

Moynul
  • 635
  • 1
  • 8
  • 30

2 Answers2

1

You're navigating into tricky waters when you call LoadAsync from within an async method. The LoadAsync method should only be called once from the UI thread. The method cannot be called again until after the LoadCompleted event is raised. Most likely your calling it a second time before the previous request is complete.

Try switching out the offending await line to something like this:

IAsyncOperation<int> asyncOp= reader.LoadAsync(512);
asyncOp.AsTask().Wait();
var count = asyncOp.GetResults();

If you want a really long answer that goes into more detail, please see this answer: https://stackoverflow.com/a/9898995/3299157

Community
  • 1
  • 1
Ageonix
  • 1,748
  • 2
  • 19
  • 32
  • I respect that answer, short and simple. Please keep in mind that I disable the button, so it cannot be called again, then put the thread to sleep for one second, and then enable the button. Is one second not enough to complete the a sync. – Moynul Feb 17 '16 at 14:43
  • Don't rely on a set amount of time because that's impossible to control. Instead, just complete your operation after the async task is complete. I updated my answer with an example. – Ageonix Feb 17 '16 at 14:57
  • I had tested your code, and after a few rallies with the server, I still got the same issue. I can visualise the problem as you said, calling await more than one time from the MAIN UI thread is bad, and the client code is doing so. Would you recommend creating a new Thread, well I believe in the Windows 8.1 API it is a Task, listening for a message from a Task fix the solution? – Moynul Feb 17 '16 at 15:03
  • Yes I would definitely try that. Unfortunately I'm not in an environment where I can test it on my end, but it sounds like you understand the issue now and I'm willing to bet that will solve the problem. – Ageonix Feb 17 '16 at 15:04
  • you have done enough, I don't expect any more. Going back to your answer, it will be marked depending if the Task does resolve it , for now thank you. – Moynul Feb 17 '16 at 15:07
  • for now I have put this on hold. I couldn't find a solution. – Moynul Feb 17 '16 at 16:16
1
             //start a new task!
            Task t = new Task(ListenForMessage);
            //if the currrent task is not completed, then return
            //this means it wont calll var count = await reader.LoadAsync(512); I.E the devil
            if (!t.IsCompleted)
                return;

            //else if the task is completed, then run it!
            t.RunSynchronously();

Thanks to Ageonix, I was able to come to this conclusion, due to his answer which caused this implementation.

Credit is given where credit is due.

Moynul
  • 635
  • 1
  • 8
  • 30