Xamarin native login with Facebook and Twitter - xamarin

I am developing a Xamarin Forms application which integrates Facebook and logs in using the Xamarin.Auth package. But each time a browser window will open to login with Facebook or Twitter.
Does Xamarin support native login with Facebook and Twitter? That is, can I log in using the Facebook or Twitter app on the user's device?
I need to get the Facebook and Twitter id of the user.

you can use ACAccountStore and if user doesn't have the social framework you can alternatively use xamarin auth
ACAccountStore accountStore = new ACAccountStore();
ACAccountType accountType = accountStore.FindAccountType(ACAccountType.Facebook);
AccountStoreOptions fbAccountStoreOptions = new AccountStoreOptions();
fbAccountStoreOptions.FacebookAppId = "333333";
fbAccountStoreOptions.SetPermissions(ACFacebookAudience.Everyone, new[] { "email", "user_birthday", "user_about_me","public_profile" });
Tuple<bool, NSError> requestResult = await accountStore.RequestAccessAsync(accountType, fbAccountStoreOptions);
if (requestResult.Item1)
{
ACAccount[] availableAccounts = accountStore.Accounts.Where(acco => acco.AccountType.Description == "Facebook").ToArray();
int fbAccountsCount = availableAccounts.Count();
if (fbAccountsCount < 1)
{
HandleFacebookAuthorizationUsingOAuthDialog();
}
else if (fbAccountsCount == 1)
{
HandleFacebookAuthorizationUsingACAccount(availableAccounts.First());
}}
private void HandleFacebookAuthorizationUsingOAuthDialog()
{
try
{
OAuth2Authenticator fbAuthenticator = new OAuth2Authenticator(SharedConstants.FacebookLiveClientId, "email,user_birthday,user_about_me", new Uri("https://m.facebook.com/dialog/oauth/"), new Uri("http://www.facebook.com/connect/login_success.html"));
fbAuthenticator.AllowCancel = true;
fbAuthenticator.Completed += FbAuthenticator_Completed;
fbAuthenticator.Error += FbAuthenticator_Error; ;
RootView.PresentViewController(fbAuthenticator.GetUI(), true, null);
}
catch (Exception ex)
{
}
}
private async void HandleFacebookAuthorizationUsingACAccount(ACAccount account)
{
try
{
NSMutableDictionary<NSString, NSString> params_ = new NSMutableDictionary<NSString, NSString>();
params_.SetValueForKey(new NSString("id,name,birthday,gender"), new NSString("fields"));
SLRequest request = SLRequest.Create(SLServiceKind.Facebook, SLRequestMethod.Get, new NSUrl($"https://graph.facebook.com/me"), params_);
request.Account = account ?? throw new ArgumentNullException(nameof(account));
SLRequestResult response = await request.PerformRequestAsync();
NSHttpUrlResponse responseData = response.Arg2;
if (responseData.StatusCode == 200)
{
string jsonResponse = response.Arg1.ToString();
FacebookAuthorizationResult authResult = ParseFacebookAuthorizationResultFromJsonResponse(jsonResponse);
_facebookAuthTCS?.TrySetResult(new SocailAutheticationResult<FacebookAuthorizationResult>(authResult));
}
else
{
_facebookAuthTCS?.TrySetResult(new SocailAutheticationResult<FacebookAuthorizationResult>(SocialAuthorizationState.CouldntConnectToService));
}
}
catch (Exception ex)
{
_
}
}

Related

Invalid state from server. Possible forgery! error in Xamarin.Auth

Why I get this error message when trying to use the Xamarin.Auth Api?
I am running on Android Plataform and using Xamarin.Forms
OAuth2Authenticator auth = new OAuth2Authenticator
(
clientId: AppKeyDropboxtoken,
scope: "",
authorizeUrl: new Uri("https://www.dropbox.com/oauth2/authorize"),
redirectUrl: new Uri(RedirectUri),
isUsingNativeUI: false
);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
// Use eventArgs.Account to do wonderful things
this.AccessToken = eventArgs.Account.Properties["access_token"].ToString();
Debug.WriteLine("AccessToken: " + this.AccessToken);
openDropboxFileList();
}
};
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(auth);
Create a class and add this code below:
public class AuthenticatorExtensions : OAuth2Authenticator
{
public AuthenticatorExtensions(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null, bool isUsingNativeUI = false) : base(clientId, clientSecret, scope, authorizeUrl, redirectUrl, accessTokenUrl, getUsernameAsync, isUsingNativeUI)
{
}
protected override void OnPageEncountered(Uri url, System.Collections.Generic.IDictionary<string, string> query, System.Collections.Generic.IDictionary<string, string> fragment)
{
// Remove state from dictionaries.
// We are ignoring request state forgery status
// as we're hitting an ASP.NET service which forwards
// to a third-party OAuth service itself
if (query.ContainsKey("state"))
{
query.Remove("state");
}
if (fragment.ContainsKey("state"))
{
fragment.Remove("state");
}
base.OnPageEncountered(url, query, fragment);
}
}
Then use it as below:
[Obsolete]
private void SignInGoogleAuth()
{
try
{
string clientId = null;
string redirectUri = null;
//Xamarin.Auth.CustomTabsConfiguration.CustomTabsClosingMessage = null;
clientId = Constants.GoogleAndroidClientId;
redirectUri = Constants.GoogleAndroidRedirectUrl;
account = store.FindAccountsForService(Constants.AppName).FirstOrDefault();
var authenticator = new AuthenticatorExtensions(
clientId,
null,
Constants.GoogleScope,
new Uri(Constants.GoogleAuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.GoogleAccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
catch (Exception ex)
{
ShowAlert("Alert", ex.Message);
}
}
[Obsolete]
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.GoogleUserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
StaticVariables.googleProfile = JsonConvert.DeserializeObject<GoogleProfile>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
Application.Current.Properties.Remove("Id");
Application.Current.Properties.Remove("FirstName");
Application.Current.Properties.Remove("LastName");
Application.Current.Properties.Remove("DisplayName");
Application.Current.Properties.Remove("EmailAddress");
Application.Current.Properties.Remove("ProfilePicture");
Application.Current.Properties.Add("Id", StaticVariables.googleProfile.Id);
Application.Current.Properties.Add("FirstName", StaticVariables.googleProfile.GivenName);
Application.Current.Properties.Add("LastName", StaticVariables.googleProfile.FamilyName);
Application.Current.Properties.Add("DisplayName", StaticVariables.googleProfile.Name);
Application.Current.Properties.Add("EmailAddress", StaticVariables.googleProfile.Email);
Application.Current.Properties.Add("ProfilePicture", StaticVariables.googleProfile.Picture);
await Navigation.PushAsync(new GoogleProfilePage());
}
}
[Obsolete]
void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
Debug.WriteLine("Authentication error: " + e.Message);
}
I was getting the infamous "Possible Forgery!" error and overrode OnPageEncountered() to work around it as many have done. This turns out to be unnecessary as well as insecure.
Oauth2Authenticator is stateful so you will get this problem if you don't use the same instance of OAuth2Authenticator to invoke OnPageLoading() as was used to initiate the authentication.
To resolve, just save the instance of OAuth2Authenticator used for initiating authentication and then reuse it when calling OnPageLoading() in your OauthInterceptor.

How to do sign out from MSAL authentication.?

I am working on xamarin forms where I am using MSAL for authentication to authenticate. Now I want to sign out the user once he clicks on the sign-out. For sign out, I wrote Below code
foreach (var user in await App.PCA.GetAccountsAsync())
{
await App.PCA.RemoveAsync(user);
}
The above code is executing without any problem but when I again try to log in it is not asking for the password. I am clearing the cookies from the app using dependency service like
created one interface in xamarin forms project
public interface IAuthentication
{
void ClearAllCookies();
}
And in the android project providing the implementation for the interface
public void ClearAllCookies()
{
CookieManager.Instance.RemoveSessionCookie();
CookieManager.Instance.RemoveAllCookie();
}
I am doing Authentication like below
In App.xamal.cs file
public static IPublicClientApplication PCA = null;
public static string ClientID = "xxxxxxxxxxxxxxxxxxxx";
public static string[] Scopes = { "User.Read" };
public App()
{
PCA = PublicClientApplicationBuilder.Create(ClientID)
.WithRedirectUri($"msal{ClientID}://auth")
.Build();
InitializeComponent();
}
//On login button click
AuthenticationResult authResult = null;
IEnumerable<IAccount> accounts = await App.PCA.GetAccountsAsync();
try
{
IAccount firstAccount = accounts.FirstOrDefault();
authResult = await App.PCA.AcquireTokenSilent(App.Scopes, firstAccount)
.ExecuteAsync();
}
catch (MsalUiRequiredException)
{
try
{
authResult = await App.PCA.AcquireTokenInteractive(App.Scopes)
.WithLoginHint(EmailId) //Here I am passing Email Id
.WithParentActivityOrWindow(App.ParentWindow)
.ExecuteAsync();
}
catch (Exception ex2)
{
await DisplayAlert("Acquire token interactive failed. See exception message for details: ", ex2.Message, "Dismiss");
}
}
if (authResult != null)
{
var content = await GetHttpContentWithTokenAsync(authResult.AccessToken);
await Navigation.PushModalAsync(new Dashboard.PartnerDashboard(content));
}
}
After clearing again it is not asking for the password. If I uninstall and reinstall the app also it is not asking for the password. How to resolve this?
Can you try with the below code for clearing accounts in MSAL.
public void ClearAllCookies(string authority)
{
var authContext = new AuthenticationContext(authority);
authContext.TokenCache.Clear();
CookieManager.Instance.RemoveSessionCookie();
CookieManager.Instance.RemoveAllCookie();
}
where authority = "https://login.windows.net/common";
Try below code before authenticate code running, for removing old accounts.
var authContext = new AuthenticationContext(authority);
if(authContext.TokenCache.ReadItems().Any())
{
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority,false, null);
}

Implement Salesforce Authentication (OAuth) in Xamarin Forms App

This article explains if anyone wants to integrate mobile app with Salesforce App and require to authenticate the app with salesforce OAuth
iOS Implementation-
Step 1: To implement Deep Link define URL Schemes in info.plist according to connected app : The callback URL
Defining URL Schemes
Step 2- Implement 'OpenUrl' method in AppDelegate to receive the deep link call in your app
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
var deepLinkURL = url;
url = null;
App myApp = App.Current as myApp.App;
if (myApp != null && deepLinkURL != null)
{
LandingPage.DeepLinkURL = deepLinkURL;
}
return true;
}
Step 3- Now you have to check whether user is coming first time or already authenticated:
public async static Task HandleDeepLink()
{
//await SecureStorage.SetAsync(AppConstant.userId, "");
/* Deep Link
* Check if user is same
* user is already loggedIn
* Token expired
*/
try
{
string data = DeepLinkURL.ToString();
if (data.Contains("userId"))
{
// extract and save all the parameters
userId = HttpUtility.ParseQueryString(DeepLinkURL.Query).Get("userId");
// if user not authenticated OR if different user
isSameAsLastUser = await oAuth.ValidateUser(userId);
if (isSameAsLastUser)
{
// is already logged in
var isUserLoggedIn = await oAuth.IsUserLoggedIn();
if (isUserLoggedIn)
{
// navigate to scan
await SecureStorage.SetAsync(AppConstant.uniqueId, uniqueId);
Application.Current.MainPage = new NavigationPage(new MainPage());
}
else
{
Application.Current.MainPage = new NavigationPage(new Authentication());
}
}
else
{
// clear previous values in secure storage
AppConfig.SaveSFParameters("false");
Application.Current.MainPage = new NavigationPage(new Authentication());
}
}
// Handle oAuth
//Extract the Code
else if (data.Contains("code"))
{
var code = HttpUtility.ParseQueryString(DeepLinkURL.Query).Get("code");
/*Exchange the code for an access token
* Save token
* LoggedInTrue
*/
if (CrossConnectivity.Current.IsConnected)
{
var authInfo = await oAuth.GetAccessToken(code);
Console.WriteLine("auth token - " + authInfo.AccessToken);
oAuth.SaveAuthInfo(authInfo);
// save user info | set user logged in to true
AppConfig.SaveSFParameters(userId,"true");
// retrieve all the parameters and pass here
Application.Current.MainPage = new NavigationPage(new MainPage(userId));
}
else
{
Device.BeginInvokeOnMainThread(async () =>
{
await Application.Current.MainPage.DisplayAlert(AppConstant.Alert, Resource.Resources.AlertMissingConnectivity, AppConstant.Ok);
});
}
}
else if (data.Contains("error"))
{
var error = HttpUtility.ParseQueryString(DeepLinkURL.Query).Get("error");
//TODO: where the user should be redirected in case of OAuth error
}
}
catch(Exception ex)
{
Device.BeginInvokeOnMainThread(() =>
{
Application.Current.MainPage.DisplayAlert("Alert", "There is some error while redirecting user to scan app, Please contact administrator", "Ok");
});
}
}
}
public partial class Authentication : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();
if (CrossConnectivity.Current.IsConnected)
{
var authUrl = Common.FormatAuthUrl(AppConfiguration.authEndPointURL,
ResponseTypes.Code, AppConfiguration.clientId,
HttpUtility.UrlEncode(AppConfiguration.redirectUri));
Browser.OpenAsync(new Uri(authUrl), BrowserLaunchMode.SystemPreferred);
}
}
}
Step 4 - Once user is authenticated successfully salesforce returns the authorization code
Step 5- Now you have to make salesforce API call to retrieve the access token by supplying the authorization code
Step 6- Once you receive the access toekn then save access token, refresh token in your app using 'Xamarin SecureStorage'
async public static void SaveAuthInfo(AuthToken authInfo)
{
try
{
await SecureStorage.SetAsync("oauth_token", authInfo.AccessToken);
await SecureStorage.SetAsync("oauth_Id", authInfo.Id);
await SecureStorage.SetAsync("oauth_InstanceUrl", authInfo.InstanceUrl);
await SecureStorage.SetAsync("oauth_RefreshToken", authInfo.RefreshToken);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
// Possible that device doesn't support secure storage on device.
}
}
Step 7 - Now redirect user to landing page

Is there any plugin or way to show 'new version of app available' alert when user opens app

I have Xamarin.Android app, I want to show alert to user (when user opens app) that please download latest version. Like other apps. How can I do that?
I have tried few ways but didn't get succeed. I have tried this. This is quite different from Android. I need it for Xamarin.
I already asked this question but existing functionality broke down due to having some changes in play store policies, consequently I am not getting specific string "itemprop=\"softwareVersion\">" from play store so I asked new question. Thank you
Working answer. I have used plugin for that Plugin.LatestVersion for Xam.Android to get latest version of app from Google play store. below line of code was returning latest app version.
var appStoreVersionString = await CrossLatestVersion.Current.GetLatestVersionNumber();
Then this is the further implementation
private void CompareVersion()
{
double currentVersion = 0d;
double appStoreversion = 0d;
bool IsUpdateRequired = false;
if (Context.PackageName != null)
{
PackageInfo info = Context.PackageManager.GetPackageInfo(Context.PackageName, PackageInfoFlags.Activities);
string currentVersionStrig = info.VersionName;
currentVersion = Convert.ToDouble(currentVersionStrig);
}
try
{
if (IsUpdateRequired == false)
{
string appStoreVersionString = string.Empty;
if (CheckNetConnection.IsNetConnected())
{
Task.Run(async () => { appStoreVersionString = await CrossLatestVersion.Current.GetLatestVersionNumber();}).Wait();
if (!string.IsNullOrEmpty(appStoreVersionString))
{
appStoreversion = Convert.ToDouble(appStoreVersionString);
if ((appStoreversion.ToString() != currentVersion.ToString() && (appStoreversion > currentVersion)))
{
IsUpdateRequired = true;
}
}
}
}
if (IsUpdateRequired)
{
Activity.RunOnUiThread(() =>
{
AlertDialog dialog = null;
var Alertdialog = new Android.App.AlertDialog.Builder(Context);
Alertdialog.SetTitle("Update Available");
Alertdialog.SetMessage($"A new version of [" + appStoreversion + "] is available. Please update to version [" + appStoreversion + "] now.");
Alertdialog.SetNegativeButton("Cancel", (sender, e) =>
{
if (dialog == null)
{
dialog = Alertdialog.Create();
}
dialog.Dismiss();
});
Alertdialog.SetPositiveButton("Update", (sender, e) =>
{
string appPackage = string.Empty;
try
{
appPackage = Application.Context.PackageName;
Utilities.Logout(Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
}
catch (ActivityNotFoundException)
{
var apppack = Application.Context.PackageName;
Utilities.Logout(Activity);
var ints = new Intent(Intent.ActionView, Android.Net.Uri.Parse("market://details?id=" + appPackage));
ints.SetFlags(ActivityFlags.ClearTop);
ints.SetFlags(ActivityFlags.NoAnimation);
ints.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(ints);
}
//this kills the app?
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
System.Environment.Exit(1);
});
if (dialog == null)
dialog = Alertdialog.Create();
dialog.Show();
});
}
}
catch (Exception ex)
{
var objLog = new LogService();
objLog.MobileLog(ex, SISConst.UserName);
}
}

Azure Notification Hub and WP8 Intermitant notifications

This is a fairly long piece of code but I am getting nowhere with this and cannot see any issues, although I am new to using notification hubs. I am trying to register for targeted notifications (the logged on user) using the notification hub in Azure. After the registration, a test notification is sent.
The issue I am having is that sometimes the notification is sent to the device, and sometimes it is not. It mostly isn't but occasionally when I step through the code on the server, i will get the notification on the emulator come through. Once when I deployed the app to my phone the notification came though on the emulator! I cannot discover a pattern.
My Controller class looks like this;
private NotificationHelper hub;
public RegisterController()
{
hub = NotificationHelper.Instance;
}
public async Task<RegistrationDescription> Post([FromBody]JObject registrationCall)
{
var obj = await hub.Post(registrationCall);
return obj;
}
And the helper class (which is used elsewhere so is not directly in the controller) looks like this;
public static NotificationHelper Instance = new NotificationHelper();
public NotificationHubClient Hub { get; set; }
// Create the client in the constructor.
public NotificationHelper()
{
var cn = "<my-cn>";
Hub = NotificationHubClient.CreateClientFromConnectionString(cn, "<my-hub>");
}
public async Task<RegistrationDescription> Post([FromBody] JObject registrationCall)
{
// Get the registration info that we need from the request.
var platform = registrationCall["platform"].ToString();
var installationId = registrationCall["instId"].ToString();
var channelUri = registrationCall["channelUri"] != null
? registrationCall["channelUri"].ToString()
: null;
var deviceToken = registrationCall["deviceToken"] != null
? registrationCall["deviceToken"].ToString()
: null;
var userName = HttpContext.Current.User.Identity.Name;
// Get registrations for the current installation ID.
var regsForInstId = await Hub.GetRegistrationsByTagAsync(installationId, 100);
var updated = false;
var firstRegistration = true;
RegistrationDescription registration = null;
// Check for existing registrations.
foreach (var registrationDescription in regsForInstId)
{
if (firstRegistration)
{
// Update the tags.
registrationDescription.Tags = new HashSet<string>() {installationId, userName};
// We need to handle each platform separately.
switch (platform)
{
case "windows":
var winReg = registrationDescription as MpnsRegistrationDescription;
winReg.ChannelUri = new Uri(channelUri);
registration = await Hub.UpdateRegistrationAsync(winReg);
break;
case "ios":
var iosReg = registrationDescription as AppleRegistrationDescription;
iosReg.DeviceToken = deviceToken;
registration = await Hub.UpdateRegistrationAsync(iosReg);
break;
}
updated = true;
firstRegistration = false;
}
else
{
// We shouldn't have any extra registrations; delete if we do.
await Hub.DeleteRegistrationAsync(registrationDescription);
}
}
// Create a new registration.
if (!updated)
{
switch (platform)
{
case "windows":
registration = await Hub.CreateMpnsNativeRegistrationAsync(channelUri,
new string[] {installationId, userName});
break;
case "ios":
registration = await Hub.CreateAppleNativeRegistrationAsync(deviceToken,
new string[] {installationId, userName});
break;
}
}
// Send out a test notification.
await SendNotification(string.Format("Test notification for {0}", userName), userName);
return registration;
And finally, my SendNotification method is here;
internal async Task SendNotification(string notificationText, string tag)
{
try
{
var toast = PrepareToastPayload("<my-hub>", notificationText);
// Send a notification to the logged-in user on both platforms.
await NotificationHelper.Instance.Hub.SendMpnsNativeNotificationAsync(toast, tag);
//await hubClient.SendAppleNativeNotificationAsync(alert, tag);
}
catch (ArgumentException ex)
{
// This is expected when an APNS registration doesn't exist.
Console.WriteLine(ex.Message);
}
}
I suspect the issue is in my phone client code, which is here and SubscribeToService is called immediately after WebAPI login;
public void SubscribeToService()
{
_channel = HttpNotificationChannel.Find("mychannel");
if (_channel == null)
{
_channel = new HttpNotificationChannel("mychannel");
_channel.Open();
_channel.BindToShellToast();
}
_channel.ChannelUriUpdated += async (o, args) =>
{
var hub = new NotificationHub("<my-hub>", "<my-cn>");
await hub.RegisterNativeAsync(args.ChannelUri.ToString());
await RegisterForMessageNotificationsAsync();
};
}
public async Task RegisterForMessageNotificationsAsync()
{
using (var client = GetNewHttpClient(true))
{
// Get the info that we need to request registration.
var installationId = LocalStorageManager.GetInstallationId(); // a new Guid
var registration = new Dictionary<string, string>()
{
{"platform", "windows"},
{"instId", installationId},
{"channelUri", _channel.ChannelUri.ToString()}
};
var request = new HttpRequestMessage(HttpMethod.Post, new Uri(ApiUrl + "api/Register/RegisterForNotifications"));
request.Content = new StringContent(JsonConvert.SerializeObject(registration), Encoding.UTF8, "application/json");
string message;
try
{
HttpResponseMessage response = await client.SendAsync(request);
message = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
message = ex.Message;
}
_registrationId = message;
}
}
Any help would be greatly appriciated as I have been stuck on this now for days! I know this is a lot of code to paste up here but it is all relevant.
Thanks,
EDIT: The SubscribeToService() method is called when the user logs in and authenticates with the WebAPI. The method is here;
public async Task<User> SendSubmitLogonAsync(LogonObject lo)
{
_logonObject = lo;
using (var client = GetNewHttpClient(false))
{
var logonString = String.Format("grant_type=password&username={0}&password={1}", lo.username, lo.password);
var sc = new StringContent(logonString, Encoding.UTF8);
var response = await client.PostAsync("Token", sc);
if (response.IsSuccessStatusCode)
{
_logonResponse = await response.Content.ReadAsAsync<TokenResponseModel>();
var userInfo = await GetUserInfoAsync();
if (_channel == null)
SubscribeToService();
else
await RegisterForMessageNotificationsAsync();
return userInfo;
}
// ...
}
}
I have solved the issue. There are tons of fairly poorly organised howto's for azure notification hubs and only one of them has this note toward the bottom;
NOTE:
You will not receive the notification when you are still in the app.
To receive a toast notification while the app is active, you must
handle the ShellToastNotificationReceived event.
This is why I was experiencing intermittent results, as i assumed you would still get a notification if you were in the app. And this little note is pretty well hidden.
Have you used proper tag / tag expressions while register/send the message. Also, Where are you storing the id back from the notification hub. It should be used when you update the channel uri (it will expire).
I would suggest to start from scratch.
Ref: http://msdn.microsoft.com/en-us/library/dn530749.aspx

Resources