Friday, June 9, 2017

Why does Navigation.PushAsync crash after Azure MobileServiceClient LoginAsync()?

Leave a Comment

Edit: Sample project that demonstrates crash can be found here: https://github.com/rringham/brokenazurexamforms - you need to set your own Azure App Service URL in:

  • src/BrokenAzureForms/Droid/Services/User/DroidUserService.cs
  • src/BrokenAzureForms/iOS/Services/User/IosUserService.cs

I'm seeing Xamarin Forms's Navigation.PushAsync() crash on Android when I attempt to use it after authenticating with Azure MobileServiceClient. This crash is isolated to Android - it does not happen on iOS.

Here's the setup - I've got a basic NavigationPage as my main app page:

MainPage = new NavigationPage(new LoginPage()); 

On my LoginPage, I authenticate using a DependencyService-injected class that performs authentication in my Android project:

private async void OnMicrosoftAccountTapped(object sender, EventArgs args) {     IUserService userService = DependencyService.Get<IUserService>();     bool authenticated = await userService.LoginWithAzureAD();     if (authenticated)     {         await Navigation.PushAsync(new HomePage(), false);     }  } 

In my Android implementation of IUserService, I do this (pretty much exactly what the Azure / Xamarin Forms tutorials show):

public async Task<bool> LoginWithAzureAD() {     try     {         _user = await _client.LoginAsync(Xamarin.Forms.Forms.Context, MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory);     }     catch (Exception)     {         return false;     }      return true; } 

Here's where things fall apart. When LoginWithAzureAD() is done, control resumes in OnMicrosoftAccountTapped(); we then go to call Navigation.PushAsync(), and boom - the app crashes, with very little detail to go on:

MobileServiceClient / Navigation crash

All I can think is that Azure MobileServiceClient is doing something pretty funky with Xamarin.Forms.Forms.Context internally, because if I remove the call to await userService.LoginWithAzureAD(), the call to Navigation.PushAsync() works with no issues. Something in MobileServiceClient is either broken, or is breaking something in Xamarin Forms.

Anyone see anything like this?

2 Answers

Answers 1

When I do this, I use the following:

In MainActivity.cs:

// Initialize for Azure Mobile Apps Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();  // Initialize for Xamarin Forms global::Xamarin.Forms.Forms.Init(this, savedInstanceState);  // Initialize for Login Provider var lp = (DroidLoginProvider)DependencyService.Get<ILoginProvider>(); lp.Initialize(this); 

Then, in my DroidLoginProvider class, I do the following:

Context _context;  public void Initialize(Context context) {     this._context = context; }  public async Task LoginAsync(MobileServiceClient client) {     await client.LoginAsync(this._context, MobileServiceAuthenticationProvider.whatever); } 

I call the LoginAsync from a Singleton wrapper in my shared project. It's important that it is a Singleton because there should only be one MobileServiceClient in a project - the authentication is stored in the MobileServiceClient.CurrentUser property and is only set on the current client.

You can see a working project with this logic here: https://github.com/adrianhall/30-days-of-zumo-v2/tree/master/file-upload

Answers 2

I think the login issue is orthogonal, and you're calling PushAsync from a background thread. You should just await the call to your dependency service method from your main thread, and then do PushAsync there.

Here's a sample:

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment