I apologize if my question is silly, but I am new to WebApi. I have followed a tutorial and published a WebApi to Azure. I also have created a Xamarin Mobile App and all the framework in Azure to be able to send Push Notifications to both Android and iOS. I have a notification hub set up, app service, web service that hosts the web api etc. Testing with Azure using the Push tab to send notifications individually to both ios and android works perfectly.
I posted the code of the web api. How can I use the web api locally on my computer to send a notification to both platforms (ios and android) please?
[RoutePrefix("sanotifications")]
public class SANotifController : ApiController
{
[HttpPost]
[Route("")]
public async Task<IHttpActionResult> SendNotificationAsync ([FromBody] string message)
{
//Get the settings for the server project
HttpConfiguration config = this.Configuration;
try
{
await InternalSendNotificationAsync(message, null);
}
catch (Exception ex)
{
//write the failure result to the logs
config.Services.GetTraceWriter().Error(ex.Message, null, "Push.SendAsync Error");
return BadRequest(ex.Message);
}
return Ok();
}
[HttpPost]
[Route("{installationid}")]
public async Task<IHttpActionResult> SendNotificationAsync(string installationId, [FromBody] string message)
{
//get the settings for the server project
HttpConfiguration config = this.Configuration;
try
{
await SendNotificationAsync(message, installationId);
}
catch (Exception ex)
{
//write the failure to the logs
config.Services.GetTraceWriter().Error(ex.Message, null, "Push.SendAsync Error");
return BadRequest(ex.Message);
}
return Ok();
}
async Task<NotificationOutcome> InternalSendNotificationAsync (string message, string installationId)
{
//Get the settings for the server project
HttpConfiguration config = this.Configuration;
//use code below if web api is already published to Azure to get existing setup
//does not work locally
var settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();
/*
//Get the Notification Hubs credentials for the Mobile App
string notificationHubName = settings.NotificationHubName;
string notificationHubConnection = settings.Connections[MobileAppSettingsKeys.NotificationHubConnectionString].ConnectionString;
*/
//the name of the Notification Hub from the overview page.
// works locally
string notificationHubName = "sa1hub";
//use "DefaultFullSharedAccessSignature" from the portal's Access Policies
string notificationHubConnection = "Endpoint=sb://sahub.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=71S2#QEWF##$";
// create a new notification hub client
var hub = NotificationHubClient.CreateClientFromConnectionString(
notificationHubConnection,
notificationHubName,
// Don't use this in RELEASE builds. The number of devices is limited.
// If TRUE, the send method will return the devices a message was
// delivered to.
enableTestSend: true);
// use a template compatible with both devices
// send the message so that all template registrations that contain "messageParam"
// will receive the notification. This includes APNS, GCM, WNS and MPNS template registrations.
var templateParams = new Dictionary<string, string>
{
["messageParam"] = message
};
// send the push notification and log the results
NotificationOutcome result = null;
if (string.IsNullOrWhiteSpace(installationId))
{
result = await hub.SendTemplateNotificationAsync(templateParams).ConfigureAwait(false);
}
else
{
result = await hub.SendTemplateNotificationAsync(templateParams, "$InstallationId:{" + installationId + "}").ConfigureAwait(false);
}
// Write the success result to the logs.
config.Services.GetTraceWriter().Info(result.State.ToString());
return result;
}
}
}
In Xamarin there are two way to send push notification from server to client. Even on Microsoft forum it's very clear step mention to Implementation.
Use of Azure Hub notification we can send easily notification on Cross mobile Platform or Native
Azure Push Notification
Another App Center Push notification Implementation.
Xamarin App Center Push Notification
To send push notification for IOS devices you have to communicate with APNS and for Android we need GCM. Azure works like an intermediate between our app and these services. So if you would like to send notification without Azure I prefer
Firebase Cloud Messaging. it is google product and allows us to send cross platform push notifications for both IOS and Android.
We can host our WebAPI in our windows local IIS and which should be configured for Firebase.
Example app for xamarin : FirebasePushNotificationPlugin
Related
I have a xamarin.forms mobile App using Microsoft.WindowsAzure.MobileServices and Microsoft.Identity.Client. Using EasyAuth I successfully got the xamarin mobile app to post data to the AzureSQL tables linked via connection string in the App Service configuration section. I use the local and offline sync methods of MobileServiceClient. I then attempted to change to B2C authentication. I setup a Tenant and under this tenant registered a new App as a native client called "MobileB2C". Redirect URIs were added automatically. I then created the signinsignup UserFlows.
Back to the Azure App Service (Mobile) under Authentication section I added a provider and selected the B2C App, MobileB2C. I did not populate the "allowed token audiences" field and Azure automatically created Client secret setting name "MICROSOFT_PROVIDER_AUTHENTICATION_SECRET" and the issuer URL.
So when I run the xamarin mobile app I can login via azure B2C and I can see that the authResult returns the users correct info along with UserIdentifier,aud, iss, sub, oid etc.
Once authResult is returned the xamarin mobile then tries to use the sync methods of MobileServiceClient to save data to the AzureSQL table. Its at this point that it fails. When the line await mClient.SyncContext.PushAsync().ConfigureAwait(false); is hit an error occurs described as Microsoft.WindowsAzure.MobileServices.Sync.MobileServicePushStatus.CancelledByAuthentication. I continued to try and confirgure the Azure back end differently and now I no linger get the CancelledByAuthentication error but instead get Microsoft.WindowsAzure.MobileServices.Sync.MobileServicePushStatus.CancelledByNetworkError.
The relevant xamarin mobile app code to implement the authentication and AzureSQL table update is as follows;
private B2CAuthenticationService()
{
// default redirectURI; each platform specific project will have to override it with its own
var builder = PublicClientApplicationBuilder.Create(B2CConstants.ClientID)
.WithB2CAuthority(B2CConstants.AuthoritySignInSignUp)
.WithIosKeychainSecurityGroup(B2CConstants.IOSKeyChainGroup)
.WithRedirectUri($"msal{B2CConstants.ClientID}://auth");
// Android implementation is based on https://github.com/jamesmontemagno/CurrentActivityPlugin
// iOS implementation would require to expose the current ViewControler - not currently implemented as it is not required
// UWP does not require this
var windowLocatorService = DependencyService.Get<IParentWindowLocatorService>();
if (windowLocatorService != null)
{
builder = builder.WithParentActivityOrWindow(() => windowLocatorService?.GetCurrentParentWindow());
}
_pca = builder.Build();
}
public async Task<UserContext> SignInAsync()
{
UserContext newContext;
try
{
// acquire token silent
newContext = await AcquireTokenSilent();
}
catch (MsalUiRequiredException)
{
// acquire token interactive
newContext = await SignInInteractively();
}
return newContext;
}
private async Task<UserContext> SignInInteractively()
{
AuthenticationResult authResult = await _pca.AcquireTokenInteractive(B2CConstants.Scopes)
.ExecuteAsync();
var newContext = UpdateUserInfo(authResult);
UserSingleton.Instance.UserId = newContext.UserIdentifier;
return newContext;
}
THe xamarin mobile app adds a record to the local database and then RefreshItemsAsync begins the synchronisation to the AzureSQL.
await azureService.AddUserSurveyAsync(newSurvey).ConfigureAwait(false);
await azureService.RefreshItemsAsync(true).ConfigureAwait(false);
It is at the PushAsync line below that the the code fails.
public async Task InitializeAsync()
{
using (await initializationLock.LockAsync())
{
if (!isInitialized)
{
mClient = new MobileServiceClient(https://mobileservice.azurewebsites.net);
// Define the offline store.
mStore = new MobileServiceSQLiteStore("mobile3.db");
mStore.DefineTable<UserSurvey>();
await mClient.SyncContext.InitializeAsync(mStore, new MobileServiceSyncHandler()).ConfigureAwait(false);
UserSurveyTable = mClient.GetSyncTable<UserSurvey>();
isInitialized = true;
}
}
}
public async Task RefreshItemsAsync(bool syncItems)
{
if (syncItems)
{
await SynchronizeAsync().ConfigureAwait(false);
}
}
public async Task SynchronizeAsync()
{
await InitializeAsync().ConfigureAwait(false);
IReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
if (!CrossConnectivity.Current.IsConnected)
return;
try
{
await mClient.SyncContext.PushAsync().ConfigureAwait(false);
await UserSurveyTable.PullAsync("usersurveys", UserSurveyTable.CreateQuery()).ConfigureAwait(false);
}
catch (MobileServicePushFailedException error)
{
if (error.PushResult != null)
{
foreach (var result in error.PushResult.Errors)
{
await ResolveError(result);
}
}
}
}
What is wrong with the Azure back end configuration or perhaps I'm missing code as I can't understand how the xamarin mobile app can then attempt to communicate with the Azure Mobile App Service and AzureSQL as I don't send any token with those lines of code for PushAsync etc or perhaps this is abstracted away?
Here are images of the exceptions;
enter image description here
enter image description here
As promised, here is the succinct version of AAD authentication. For your purposes, B2C authentication is the same as AAD authentication.
There are two application definitions at play here - one for the mobile application (which basically says "this person is authenticated"), and one for the service (which says "a token authenticated for this mobile application can access this service"). So, you create an application ID for your mobile application, and an application ID for your service, and then you configure the service application ID to accept the mobile application.
The "WPF" tutorial for Azure Mobile Apps gives the general overview, although it's for WPF instead of Xamarin. The pieces you need are all the same.
The "WPF" tutorial here: https://learn.microsoft.com/en-us/azure/developer/mobile-apps/azure-mobile-apps/quickstarts/wpf/authentication
I'm implementing Azure SignalR service in my ASP.NET Core 2.2 app with React front-end. When I send a message, I'm NOT getting any errors but my messages are not reaching the Azure SignalR service.
To be specific, this is a private chat application so when a message reaches the hub, I only need to send it to participants in that particular chat and NOT to all connections.
When I send a message, it hits my hub but I see no indication that the message is making it to the Azure Service.
For security, I use Auth0 JWT Token authentication. In my hub, I correctly see the authorized user claims so I don't think there's any issues with security. As I mentioned, the fact that I'm able to hit the hub tells me that the frontend and security are working fine.
In the Azure portal however, I see no indication of any messages but if I'm reading the data correctly, I do see 2 client connections which is correct in my tests i.e. two open browsers I'm using for testing. Here's a screen shot:
Here's my Startup.cs code:
public void ConfigureServices(IServiceCollection services)
{
// Omitted for brevity
services.AddAuthentication(options => {
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwtOptions => {
jwtOptions.Authority = authority;
jwtOptions.Audience = audience;
jwtOptions.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// Check to see if the message is coming into chat
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/im")))
{
context.Token = accessToken;
}
return System.Threading.Tasks.Task.CompletedTask;
}
};
});
// Add SignalR
services.AddSignalR(hubOptions => {
hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(10);
}).AddAzureSignalR(Configuration["AzureSignalR:ConnectionString"]);
}
And here's the Configure() method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Omitted for brevity
app.UseSignalRQueryStringAuth();
app.UseAzureSignalR(routes =>
{
routes.MapHub<Hubs.IngridMessaging>("/im");
});
}
Here's the method I use to map a user's connectionId to the userName:
public override async Task OnConnectedAsync()
{
// Get connectionId
var connectionId = Context.ConnectionId;
// Get current userId
var userId = Utils.GetUserId(Context.User);
// Add connection
var connections = await _myServices.AddHubConnection(userId, connectionId);
await Groups.AddToGroupAsync(connectionId, "Online Users");
await base.OnConnectedAsync();
}
Here's one of my hub methods. Please note that I'm aware a user may have multiple connections simultaneously. I just simplified the code here to make it easier to digest. My actual code accounts for users having multiple connections:
[Authorize]
public async Task CreateConversation(Conversation conversation)
{
// Get sender
var user = Context.User;
var connectionId = Context.ConnectionId;
// Send message to all participants of this chat
foreach(var person in conversation.Participants)
{
var userConnectionId = Utils.GetUserConnectionId(user.Id);
await Clients.User(userConnectionId.ToString()).SendAsync("new_conversation", conversation.Message);
}
}
Any idea what I'm doing wrong that prevents messages from reaching the Azure SignalR service?
It might be caused by misspelled method, incorrect method signature, incorrect hub name, duplicate method name on the client, or missing JSON parser on the client, as it might fail silently on the server.
Taken from Calling methods between the client and server silently fails
:
Misspelled method, incorrect method signature, or incorrect hub name
If the name or signature of a called method does not exactly match an appropriate method on the client, the call will fail. Verify that the method name called by the server matches the name of the method on the client. Also, SignalR creates the hub proxy using camel-cased methods, as is appropriate in JavaScript, so a method called SendMessage on the server would be called sendMessage in the client proxy. If you use the HubName attribute in your server-side code, verify that the name used matches the name used to create the hub on the client. If you do not use the HubName attribute, verify that the name of the hub in a JavaScript client is camel-cased, such as chatHub instead of ChatHub.
Duplicate method name on client
Verify that you do not have a duplicate method on the client that differs only by case. If your client application has a method called sendMessage, verify that there isn't also a method called SendMessage as well.
Missing JSON parser on the client
SignalR requires a JSON parser to be present to serialize calls between the server and the client. If your client doesn't have a built-in JSON parser (such as Internet Explorer 7), you'll need to include one in your application.
Update
In response to your comments, I would suggest you try one of the Azure SignalR samples, such as
Get Started with SignalR: a Chat Room Example to see if you get the same behavior.
Hope it helps!
I hope help me to fund a good tutorial for send push notification to android app using php without external cloud like firebase , just php in my localhost to Android app
If yes, how can I do it?
You couldn't push notification without using cloud service, but you can request for some data from a server and get a response without using cloud service. You can use network libray like volley and retrofit. Here I shows an example of volley
Add the following dependency in your app gradle
dependencies {
compile 'com.android.volley:volley:1.0.0'
}
Add internet permission in your manifest
<uses-permission android:name="android.permission.INTERNET" />
And add the following in your activity
//specify url
String url = "https:yourIpAddress/file.php";
// make a request
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, response.toString());
//Success
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//Error
}
});
//Make a request queue
RequestQueue mRequestQueue = Volley.newRequestQueue(getApplicationContext());
//Add request to requestQueue
mRequestQueue.add(jsonObjReq);
For more details refer enter link description here
I am written code to send push notification to windows phone 8 by azure notification hub.
i am able to send to the toast notification to windows phone 8 and windows phone 8 also able to get notification . but when i am sending tile notification, it is sending tile notification successfully, but windows phone 8 is not getting this tile notification.
i already used BindToShellTile and BindToShellToast at the time of getting the channel Uri and after that i am doing the registration by this channel uri and checked IDCAPPUSH_NOTIFICATION the capabilities in windowsphone porject manifest to allow the push notification.
Below my Code for Bind the Device to Tile And Toast.
public void GetNotificationChannel()
{
/// Holds the push channel that is created or found.
HttpNotificationChannel pushChannel;
// The name of our push channel.
string channelName = "ToastChannel";
// Try to find the push channel.
pushChannel = HttpNotificationChannel.Find(channelName);
// If the channel was not found, then create a new connection to the push service.
if (pushChannel == null)
{
pushChannel = new HttpNotificationChannel(channelName);
// Register for all the events before attempting to open the channel.
pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
// Register for this notification only if you need to receive the notifications while your application is running.
pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);
pushChannel.Open();
// Bind this new channel for toast and tile notifications.
pushChannel.BindToShellToast();
pushChannel.BindToShellTile();
}
else
{
// The channel was already open, so just register for all the events.
pushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
pushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
// Register for this notification only if you need to receive the notifications while your application is running.
pushChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(PushChannel_ShellToastNotificationReceived);
// Display the URI for testing purposes. Normally, the URI would be passed back to your web service at this point.
System.Diagnostics.Debug.WriteLine(pushChannel.ChannelUri.ToString());
//MessageBox.Show(String.Format("Channel Uri is {0}",
// pushChannel.ChannelUri.ToString()));
}
}
Below Code is sued to registered this device in notification hub.
// notification tois nothing but channel uri
private static async void WindowsPhoneRegistrations(string notificationToken)
{
try
{
var notificationHub = GetNotificationHubClient();
// this wil retunr the notification hub client by using the notificationconnectionstring // and hub path
var windowsPhoneRegistrationDescription = await notificationHub.CreateMpnsNativeRegistrationAsync();
}
catch (Exception ex)
{
throw;
}
}
Below code is for sending the tile notification
private static async void SendWindowsPhone8ToastNotification()
{
try
{
string windowsPhone8ToastFinalTemplate = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\" Version=\"2.0\">" +
"<wp:Tile Id=\"txt1\" Template=\"IconicTile\">" +
"<wp:SmallIconImage>http://flyosity.com/images/_blogentries/networkicon/step2.png</wp:SmallIconImage>" +
"<wp:IconImage>http://flyosity.com/images/_blogentries/networkicon/step2.png</wp:IconImage>" +
"<wp:WideContent1 >This is sample</wp:WideContent1>" +
"<wp:Count >1</wp:Count>" +
"<wp:Title >Good</wp:Title>" +
"</wp:Tile>" +
"</wp:Notification>";
var notificationHub = GetNotificationHubClient();
NotificationOutcome n = await notificationHub.SendMpnsNativeNotificationAsync(HttpUtility.HtmlEncode(windowsPhone8ToastFinalTemplate));
}
catch (Exception ex)
{
throw;
}
}
I am able to send the tile notification to notification hubs with out any exceptions and getting the status from notification hub after sending . but device is not getting the tile notification.
what i missed out or did mistake somewhere in this code to get the tile notification in windows phone 8. please help.
i just came up with a new problem but the same context azure. now i am trying to implement Multilinqual(localized) push notifications so i am following this localized push notification so this link inculde lot of work of making categories i just wanted to omit them so i am trying to use direct code for subscribing the toast notification on the basis of tag given in Bachend clien app that generate toast notification...here is Backend client app code..
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("Endpoint=sb://samplenotificationhub-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=", "samplenotificationhub");
var notification = new Dictionary<string, string>() {
{"News_English", "World News in English!"},
{"News_French", "World News in French!"},
{"News_Mandarin", "World News in Mandarin!"}};
await hub.SendTemplateNotificationAsync(notification, "World");
first i tried it on my previously working sample app that can receive Push notification on the basis of tags also so i just tried to update its code to get template based toaste notification but unfortunately i am not getting anything..here is the code..
private void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("mychannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("mychannel");
CurrentChannel.Open();
CurrentChannel.BindToShellToast();
CurrentChannel.BindToShellTile();
}
CurrentChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(async (o, args) =>
{
var tags = new HashSet<string>();
tags.Add("World");
var hub = new NotificationHub("samplenotificationhub", "Endpoint=sb://samplenotificationhub-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=");
var template = String.Format(#"<toast><visual><binding template=""ToastText01""><text id=""1"">$(News_English)</text></binding></visual></toast>");
await hub.RegisterTemplateAsync(args.ChannelUri.ToString(),template,"hello", tags);
// await hub.RegisterNativeAsync(args.ChannelUri.ToString(),tags);
});
}
so if you know anything about it..please guide me any kind of help or suggetion is appreciated..
Hello Friends I again able to solve my problem so the mistake i am doing here is i am following the link blindly as it is for Windows store apps and i wanted to implemented the same for windows phone 8 so what i am doing wrong is using the same Tamplate that is used in windows store apps for windows phone 8 too. so what i understand is this if wanted to target the multiple platforms from a notification hub then your client app that send the toast notification has the same notification for all but all your platform will handle it differently Like for windows 8 the tamplate i am using will work but windows phone this template will work.
string toast = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Toast>" +
"<wp:Text1>Hello Windows phone</wp:Text1>" +
"</wp:Toast> " +
"</wp:Notification>";
so different platform will have different platform.hope it help somebody else too.