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:
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:
0 comments:
Post a Comment