0

I have a page - Page A, that has a method that subscribes to an event on another page - Page B. I figured I could instantiate Page B in my code in Page A before having my method in Page A subscribe to the event in Page B, and then finally pushing Page B to the navigation stack.

Unfortunately, I keep getting a NullReferenceException on the line in which the method subscribes to the event when I test my application on iOS. The code runs perfectly fine when I deploy and test as an Android application, but I always get the NullReferenceException on iOS. What's causing this exception to be thrown, and how can I fix it? Why is it platform specific to iOS?

Code on Page A

var confirmationPage = new EmailConfirmationPage(username);
confirmationPage.EmailConfirmed += this.OnEmailConfirmed;
await this.Navigation.PushModalAsync(confirmationPage);

...

private void OnEmailConfirmed(object source, EventArgs args)
{
    this.LabelMessage.Text = "Email Confirmed!";
}

Code on Page B

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace appFBLA2019
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class EmailConfirmationPage : ContentPage
    {
        private string username;
        private string email;

        public delegate void EmailConfirmedEventHandler(object source, EventArgs args);
        public event EmailConfirmedEventHandler EmailConfirmed;

        public EmailConfirmationPage(string username)
        {
            InitializeComponent();
            this.username = username;
            this.LabelTitle.Text = "Loading...";
            GetEmail();
        }

        private void GetEmail()
        {
            try
            {
                ServerConnector.QueryDB($"getEmail/{this.username}/-");
                this.email = ServerConnector.ReceiveFromDB();
                this.LabelTitle.Text = $"Enter the confirmation code sent to {this.email.Split('/')[1]}";
            }
            catch
            {
                this.LabelMessage.Text = "Connection Error: Please Try Again.";
            }
        }

        private async void ButtonConfirmEmail_Clicked(object sender, EventArgs e)
        {
            try
            {
                string userInputToken = this.EntryConfirmationCode.Text.Trim();
                ServerConnector.QueryDB($"confirmEmail/{this.username}/{userInputToken}/-");
                string returnData = ServerConnector.ReceiveFromDB();

                if (returnData == "true/-")
                {
                    OnEmailConfirmed();
                    await this.Navigation.PopModalAsync(true);
                }
                else
                {
                    this.LabelMessage.Text = "Email could not be confirmed. Please try your code again.";
                }
            }
            catch
            {
                this.LabelMessage.Text = "Connection Error: Please try again.";
            }
        }

        private void ButtonFixEmail_Clicked(object sender, EventArgs e)
        {
            string newEmail = this.EntryChangeEmail.Text;
            ServerConnector.QueryDB($"changeEmail/{this.username}/{newEmail}/-");
            string result = ServerConnector.ReceiveFromDB();

            if (result == "true/-")
            {
                this.LabelMessage.Text = $"Enter the confirmation code sent to {newEmail}";
            }
            else
            {
                this.LabelMessage.Text = $"Email could not be changed: {result.Split('/')[1]}";
            }
        }

        private async void ButtonClose_Clicked(object sender, EventArgs e)
        {
            await this.Navigation.PopModalAsync(true);
        }

        protected virtual void OnEmailConfirmed()
        {
            EmailConfirmed?.Invoke(this, EventArgs.Empty);
        }
    }
}

Call Stack before subscribing method to event:

0xC0 in appFBLA2019.CreateAccountPage.ButtonCreateAccount_Clicked at C:\Users\chung\source\repos\appFBLA2019\appFBLA2019\appFBLA2019\CreateAccountPage.xaml.cs:30,21 C#

Call stack after subscribing method to event:

0x1B8 in appFBLA2019.CreateAccountPage.ButtonCreateAccount_Clicked at C:\Users\chung\source\repos\appFBLA2019\appFBLA2019\appFBLA2019\CreateAccountPage.xaml.cs:39,13 C#

chungmcl
  • 310
  • 1
  • 3
  • 14
  • 2
    Please show the entire Page B and just to confirm page B is the ```EmailConfirmationPage``` correct? – Michael Puckett II Aug 09 '18 at 22:54
  • I have updated the post to include the entirety of Page B, and yes, EmailConfirmationPage is Page B. Thank you! @MichaelPuckettII – chungmcl Aug 10 '18 at 20:09
  • Don't use async void! – Poul Bak Aug 10 '18 at 20:22
  • Does ConfirmationPage construct properly? Looks like an exception during construction will call navigation.PopModalAsync but I don't know xamarin so I don't know what that will do – MarcE Aug 10 '18 at 20:40
  • Could you please elaborate on why I shouldn't use async void in this situation? For my current code, it requires the use of it. Thanks! @PoulBak – chungmcl Aug 10 '18 at 20:51
  • EmailConfirmationPage does appear to construct and be pushed to the navigation stack properly when I do not attempt to subscribe my method to the event. @MarcE – chungmcl Aug 10 '18 at 20:52
  • @chungm7 [Why exactly is async void bad?](https://stackoverflow.com/a/45449457/4934172) And no, it's not required for all cases in your code (e.g., `GetEmail()`). [Void-returning async methods have a specific purpose: to make asynchronous event handlers possible](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx). Therefore, it's only right in your button click events. – 41686d6564 stands w. Palestine Aug 10 '18 at 20:57
  • Read https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html about async constructors. – Poul Bak Aug 10 '18 at 21:04
  • The await / async call from the constructor looks weird to me. I wonder if somehow it's not fully constructed by the time you try to attach the event (although I don't know how that's possible) – MarcE Aug 10 '18 at 21:06
  • Thanks for letting me know about the issues with async void everyone, but even after dealing with that error, I'm still getting the NullReferenceException on the same line. I found a solution around having to use async in the constructor and removed any async code there, but I am still dealing with the same issue. – chungmcl Aug 10 '18 at 21:33
  • Please post the updated code for EmailConfirmationPage and the call stack for the exception. – DavidS Aug 11 '18 at 04:03
  • @DavidS I have posted the updated code and the call stacks. Thank you! I have also just noticed that this issue only occurs on iOS. When I deployed to Android I encountered no issues with the NullReferenceException, and my code functioned as it should have. – chungmcl Aug 11 '18 at 19:35
  • Add the exception message and the call stack for that also. – Michael Puckett II Aug 12 '18 at 14:08
  • I would try removing ```GetEmail``` from the constructor and testing it again. It looks good to me but maybe there's something quirky about how iOS handles exceptions during construction or the timing; since you're requesting email at that time. I have no idea honestly so I'm reaching.... – Michael Puckett II Aug 12 '18 at 14:13

1 Answers1

0

Upon further testing, I noticed that this issue occurs on both iOS and Android, but ONLY when running the application with Xamarin Live Player. I contacted Microsoft and they pointed out that Xamarin Live Player unfortunately has limitations. Deploying directly to a device causes no issues, and the code runs fine.

chungmcl
  • 310
  • 1
  • 3
  • 14