How to send Android push notifications via GCM on C# .Net - c#
I'm new to all Android GCM push notifications and I have read stack posts but couldn't get a straight answer.I have also read Create push notification in android to get a better understanding of how GCM works. I have also used the gcm-demo-server and gcm-demo-client provided by the SDK. However, here are my doubts and what I have tried so far:
Regarding the link I have put, the phone which has the app registers to get the registration key. Is this a unique key for all phones which uses the same app?
Does this registration key expires in any case? (E.g. App running on background)
Assuming that I have the registration key, I have tried the following code snippet to push notification via GCM to my app. This is written on c# .net. Please let me know whether what I have mentioned above can be achieved using the following code snippet:
private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json")
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
// MESSAGE CONTENT
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// CREATE REQUEST
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
Request.Method = "POST";
Request.KeepAlive = false;
Request.ContentType = postDataContentType;
Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
Request.ContentLength = byteArray.Length;
Stream dataStream = Request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// SEND MESSAGE
try
{
WebResponse Response = Request.GetResponse();
HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
{
var text = "Unauthorized - need new token";
}
else if (!ResponseCode.Equals(HttpStatusCode.OK))
{
var text = "Response from web service isn't OK";
}
StreamReader Reader = new StreamReader(Response.GetResponseStream());
string responseLine = Reader.ReadToEnd();
Reader.Close();
return responseLine;
}
catch (Exception e)
{
}
return "error";
}
Is there a direct way of sending push notifications without the phone first being registered in our custom server?
Refer Code:
public class AndroidGCMPushNotification
{
public AndroidGCMPushNotification()
{
//
// TODO: Add constructor logic here
//
}
public string SendNotification(string deviceId, string message)
{
string SERVER_API_KEY = "server api key";
var SENDER_ID = "application number";
var value = message;
WebRequest tRequest;
tRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
tRequest.Method = "post";
tRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8";
tRequest.Headers.Add(string.Format("Authorization: key={0}", SERVER_API_KEY));
tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));
string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "®istration_id=" + deviceId + "";
Console.WriteLine(postData);
Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
tRequest.ContentLength = byteArray.Length;
Stream dataStream = tRequest.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse tResponse = tRequest.GetResponse();
dataStream = tResponse.GetResponseStream();
StreamReader tReader = new StreamReader(dataStream);
String sResponseFromServer = tReader.ReadToEnd();
tReader.Close();
dataStream.Close();
tResponse.Close();
return sResponseFromServer;
}
}
Referance Link:
http://www.codeproject.com/Tips/434338/Android-GCM-Push-Notification
Code looks bit long but it works. I just sent a push notification to my phone after struggling 2 days by implementing the following code in C# project. I referred a link regarding this implementation, But couldn't find it to post here. So will share my code with you. If you want to test the Notification online you may visit to this link.
note : I have hardcorded apiKey, deviceId and postData, please pass
the apiKey,deviceId and postData in your request and remove them from
the method body. If you want pass message string also
public string SendGCMNotification(string apiKey, string deviceId, string postData)
{
string postDataContentType = "application/json";
apiKey = "AIzaSyC13...PhtPvBj1Blihv_J4"; // hardcorded
deviceId = "da5azdfZ0hc:APA91bGM...t8uH"; // hardcorded
string message = "Your text";
string tickerText = "example test GCM";
string contentTitle = "content title GCM";
postData =
"{ \"registration_ids\": [ \"" + deviceId + "\" ], " +
"\"data\": {\"tickerText\":\"" + tickerText + "\", " +
"\"contentTitle\":\"" + contentTitle + "\", " +
"\"message\": \"" + message + "\"}}";
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
//
// MESSAGE CONTENT
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//
// CREATE REQUEST
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
Request.Method = "POST";
Request.KeepAlive = false;
Request.ContentType = postDataContentType;
Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
Request.ContentLength = byteArray.Length;
Stream dataStream = Request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
//
// SEND MESSAGE
try
{
WebResponse Response = Request.GetResponse();
HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
{
var text = "Unauthorized - need new token";
}
else if (!ResponseCode.Equals(HttpStatusCode.OK))
{
var text = "Response from web service isn't OK";
}
StreamReader Reader = new StreamReader(Response.GetResponseStream());
string responseLine = Reader.ReadToEnd();
Reader.Close();
return responseLine;
}
catch (Exception e)
{
}
return "error";
}
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}
You may not familiar with words like apiKey, deviceId. Dont worry i will explain what are they and how to create those.
apiKey What & why :This a key that will be used when sending requests to GCM server. How to create : Refer this post
deviceId What & why : This id also known as RegistrationId. This is a unique id to identify the device. When you want to send a
notification to a specific device you need this id. How to
create: This depends on how you implement the application. For cordova
i used a simple pushNotification Plugin You can simply create a
deviceId/RegistrationId using this plugin. To do that you need to have
a senderId. Google how to create a senderId it is really simple =)
If anyone needs some help leave a comment.
Happy Coding.
-Charitha-
Just for the information for new visitors on this post, if you want to send same message to multiple devices then simply send comma separated device ids in registration_id parameter of request.
Here is a nice article on this
http://www.codewithasp.net/2015/11/send-message-gcm-c-sharp-single-multiple.html
This never worked for me and it is hard to debug plus passing a list of registration token is not clear -would expect passing a string array instead of comma separated string - , the fact that this is very simple post request i created my own class with a method that return the server response, and it works very well:
Usage
//Registration Token
string[] registrationIds ={"diks4vp5......","erPjEb9....."};
AndroidGcmPushNotification gcmPushNotification = new
AndroidGcmPushNotification(
"API KEY", registrationIds, "Hello World"
);
gcmPushNotification.SendGcmNotification();
Class
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
public class AndroidGcmPushNotification
{
private readonly string _apiAccessKey;
private readonly string[] _registrationIds;
private readonly string _message;
private readonly string _title;
private readonly string _subtitle;
private readonly string _tickerText;
private readonly bool _vibrate;
private readonly bool _sound;
public AndroidGcmPushNotification(string apiAccessKey, string[] registrationIds, string message, string title = "",
string subtitle = "", string tickerText = "", bool vibrate = true, bool sound = true )
{
_apiAccessKey = apiAccessKey;
_registrationIds = registrationIds;
_message = message;
_title = title;
_subtitle = subtitle;
_tickerText = tickerText;
_vibrate = vibrate;
_sound = sound;
}
public string SendGcmNotification()
{
//MESSAGE DATA
GcmPostData data = new GcmPostData()
{
message = _message,
title = _title,
subtitle = _subtitle,
tickerText = _tickerText,
vibrate = _vibrate,
sound = _sound
};
//MESSAGE FIELDS
GcmPostFields fields = new GcmPostFields();
fields.registration_ids = _registrationIds;
fields.data = data;
//SERIALIZE TO JSON
JavaScriptSerializer jsonEncode = new JavaScriptSerializer();
//CONTENTS
byte[] byteArray = Encoding.UTF8.GetBytes(jsonEncode.Serialize(fields));
//REQUEST
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
request.Method = "POST";
request.KeepAlive = false;
request.ContentType = "application/json";
request.Headers.Add($"Authorization: key={_apiAccessKey}");
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
//SEND REQUEST
try
{
WebResponse response = request.GetResponse();
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseLine = reader.ReadToEnd();
reader.Close();
return responseLine;
}
}
catch (Exception e)
{
return e.Message;
}
}
private class GcmPostFields
{
public string[] registration_ids { get; set; }
public GcmPostData data { get; set; }
}
private class GcmPostData
{
public string message { get; set; }
public string title { get; set; }
public string subtitle { get; set; }
public string tickerText { get; set; }
public bool vibrate { get; set; }
public bool sound { get; set; }
}
}
There is package PushSharp.
Allows to communicate with almost every popular notification api.
Example code:
// Configuration
var config = new GcmConfiguration ("GCM-SENDER-ID", "AUTH-TOKEN", null);
// Create a new broker
var gcmBroker = new GcmServiceBroker (config);
// Wire up events
gcmBroker.OnNotificationFailed += (notification, aggregateEx) => {
aggregateEx.Handle (ex => {
// See what kind of exception it was to further diagnose
if (ex is GcmNotificationException) {
var notificationException = (GcmNotificationException)ex;
// Deal with the failed notification
var gcmNotification = notificationException.Notification;
var description = notificationException.Description;
Console.WriteLine ($"GCM Notification Failed: ID={gcmNotification.MessageId}, Desc={description}");
} else if (ex is GcmMulticastResultException) {
var multicastException = (GcmMulticastResultException)ex;
foreach (var succeededNotification in multicastException.Succeeded) {
Console.WriteLine ($"GCM Notification Failed: ID={succeededNotification.MessageId}");
}
foreach (var failedKvp in multicastException.Failed) {
var n = failedKvp.Key;
var e = failedKvp.Value;
Console.WriteLine ($"GCM Notification Failed: ID={n.MessageId}, Desc={e.Description}");
}
} else if (ex is DeviceSubscriptionExpiredException) {
var expiredException = (DeviceSubscriptionExpiredException)ex;
var oldId = expiredException.OldSubscriptionId;
var newId = expiredException.NewSubscriptionId;
Console.WriteLine ($"Device RegistrationId Expired: {oldId}");
if (!string.IsNullOrWhitespace (newId)) {
// If this value isn't null, our subscription changed and we should update our database
Console.WriteLine ($"Device RegistrationId Changed To: {newId}");
}
} else if (ex is RetryAfterException) {
var retryException = (RetryAfterException)ex;
// If you get rate limited, you should stop sending messages until after the RetryAfterUtc date
Console.WriteLine ($"GCM Rate Limited, don't send more until after {retryException.RetryAfterUtc}");
} else {
Console.WriteLine ("GCM Notification Failed for some unknown reason");
}
// Mark it as handled
return true;
});
};
gcmBroker.OnNotificationSucceeded += (notification) => {
Console.WriteLine ("GCM Notification Sent!");
};
// Start the broker
gcmBroker.Start ();
foreach (var regId in MY_REGISTRATION_IDS) {
// Queue a notification to send
gcmBroker.QueueNotification (new GcmNotification {
RegistrationIds = new List<string> {
regId
},
Data = JObject.Parse ("{ \"somekey\" : \"somevalue\" }")
});
}
// Stop the broker, wait for it to finish
// This isn't done after every message, but after you're
// done with the broker
gcmBroker.Stop ();
I have worked with Android Applications and IOS application using Firebase's FCM.
This code is working .Middle layer is ASP.NET API.You start a project in visual studio and select API.To be create a controller.Your server_api_key and sender id adding Web.config file.
Adding user fcm server_api_key and sender id.
<appSettings>
<add key="SERVER_API_KEY" value=""/>
<add key="SENDER_ID" value=""/>
</appSettings>
The below code to add your controller
using System;
using System.Net;
using System.Web.Http;
using System.Web.Script.Serialization;
using System.Configuration;
using System.IO;
namespace pushios.Controllers
{
public class HomeController : ApiController
{
[HttpGet]
[Route("sendmessage")]
public IHttpActionResult SendMessage()
{
var data = new {
to = "Device Token",
data = new
{
//To be adding your json data
body="Test",
confId= "",
pageTitle= "test",
pageFormat= "",
dataValue= "",
title= "C#",
webviewURL= "",
priority = "high",
notificationBlastID = "0",
status = true
}
};
SendNotification(data);
return Ok();
}
public void SendNotification(object data)
{
var Serializer = new JavaScriptSerializer();
var json = Serializer.Serialize(data);
Byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(json);
SendNotification(byteArray);
}
public void SendNotification(Byte[] byteArray)
{
try
{
String server_api_key = ConfigurationManager.AppSettings["SERVER_API_KEY"];
String senderid = ConfigurationManager.AppSettings["SENDER_ID"];
WebRequest type = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
type.Method = "post";
type.ContentType = "application/json";
type.Headers.Add($"Authorization: key={server_api_key}");
type.Headers.Add($"Sender: id={senderid}");
type.ContentLength = byteArray.Length;
Stream datastream = type.GetRequestStream();
datastream.Write(byteArray, 0, byteArray.Length);
datastream.Close();
WebResponse respones = type.GetResponse();
datastream = respones.GetResponseStream();
StreamReader reader = new StreamReader(datastream);
String sresponessrever = reader.ReadToEnd();
reader.Close();
datastream.Close();
respones.Close();
}
catch (Exception)
{
throw;
}
}
}
}
Related
I am trying to Access the private Poloniex trading API in Unity C# but am getting the error "invalid command"
I am trying to Access the private Poloniex trading API in Unity C# but am getting the error "invalid command" I have my API Key and Secret authorized on Poloniex for the Trading API but can't seem to get access with my current code: using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Security.Cryptography; public class PolonScript : MonoBehaviour { public TextMesh OutputText; const string _apiKey = "---Key---"; const string _apiSecret = "---secret---"; void Start () { string nonce = DateTime.Now.ToString("HHmmss"); string myParam = "command=returnBalances&nonce=" + nonce; const string WEBSERVICE_URL = "https://poloniex.com/tradingApi"; try { var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL); if (webRequest != null) { webRequest.Method = "POST"; webRequest.Timeout = 12000; webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.Headers.Add("Key", _apiKey); webRequest.Headers.Add("Sign", genHMAC(myParam)); webRequest.Headers.Add("command", "returnBalances"); webRequest.Headers.Add("nonce", nonce.ToString()); using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream()) { using (System.IO.StreamReader sr = new System.IO.StreamReader(s)) { var jsonResponse = sr.ReadToEnd(); OutputText.text = jsonResponse.ToString(); } } } } catch (Exception ex) { OutputText.text = ex.ToString(); } } //end-of-start() Here is my current signing method which I am quite sure has a mistake (Human error) within, am I doing something wrong obliviously here? private string genHMAC(string message) { byte [] APISecret_Bytes = System.Text.Encoding.UTF8.GetBytes(_apiSecret); byte [] MESSAGE_Bytes = System.Text.Encoding.UTF8.GetBytes(message); var hmac = new HMACSHA512(APISecret_Bytes); var hashmessage = hmac.ComputeHash(MESSAGE_Bytes); var sign = BitConverter.ToString(hashmessage).Replace("-", "").ToLower(); return sign; } }
Poloniex Command should not be sent in the header, you should send it as a POST parameter, that's why it's responding "invalid command". Take a look at this answer to see how you send POST parameters in c#:How to add parameters into a WebRequest? Here's an example of how your Start method should look like: void Start() { string nonce = DateTime.Now.ToString("HHmmss"); string myParam = "command=returnBalances&nonce=" + nonce; const string WEBSERVICE_URL = "https://poloniex.com/tradingApi"; try { var webRequest = System.Net.WebRequest.Create(WEBSERVICE_URL); if (webRequest != null) { webRequest.Method = "POST"; webRequest.Timeout = 12000; webRequest.ContentType = "application/x-www-form-urlencoded"; webRequest.Headers.Add("Key", _apiKey); webRequest.Headers.Add("Sign", genHMAC(myParam)); byte[] dataStream = Encoding.UTF8.GetBytes($"command=returnBalances&nonce={nonce.ToString()}"); webRequest.ContentLength = dataStream.Length; Stream newStream = webRequest.GetRequestStream(); newStream.Write(dataStream, 0, dataStream.Length); newStream.Close(); using (System.IO.Stream s = webRequest.GetResponse().GetResponseStream()) { using (System.IO.StreamReader sr = new System.IO.StreamReader(s)) { var jsonResponse = sr.ReadToEnd(); OutputText.text = jsonResponse.ToString(); } } } } catch (Exception ex) { OutputText.text = ex.ToString(); } }
Google reCaptcha in Web API 2 c#
I have an ASP.NET Web API 2 Project. I am trying to read Google Captcha from the form. I tried this Code: public string Post(FoundingRequest model) { var response = Request["g-recaptcha-response"]; string secretKey = "my key"; var client = new WebClient(); var result = client.DownloadString( $"https://www.google.com/recaptcha/api/siteverify?secret={secretKey}&response={response}"); var obj = JObject.Parse(result); model.Captcha = (bool)obj.SelectToken("success"); .... } but I am receiving an Error on the first line: Cannot apply indexing with [] to an expression of type 'HttpRequestMessage' why? and how to solve it? thank you
That method's body for me works fine: const string secretKey = "YOUR KEY"; string responseFromServer = ""; HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://www.google.com/recaptcha/api/siteverify?secret=" + secretKey + "&response=" + response); using (WebResponse resp = req.GetResponse()) using (Stream dataStream = resp.GetResponseStream()) { if (dataStream != null) { using (StreamReader reader = new StreamReader(dataStream)) { // Read the content. responseFromServer = reader.ReadToEnd(); } } } dynamic jsonResponse = new JavaScriptSerializer().DeserializeObject(responseFromServer); return jsonResponse == null || bool.Parse(jsonResponse["success"].ToString()); Update Regarding the comment, it can be checked on the client side var response = window.grecaptcha.getResponse() And then pass this variable to Web API This is part of my client script: if (typeof window.grecaptcha != 'undefined') { var capResponse = window.grecaptcha.getResponse(); if (!capResponse || capResponse.length === 0) { user.isCaptchaPassed = false; //alert("Captcha not Passed"); return false; } user.gReCaptcha = capResponse; } "user" is JS object created before, which passed through JS to server. (AJAX call)
Here's how I did it. I don't use the ChallangeTs so I didn't bother trying to figure out why it wasn't converting to DateTime properly. Maybe someone else has that solved. public class ReCaptchaResponse { public bool Success; public string ChallengeTs; public string Hostname; public object[] ErrorCodes; } [HttpPost] [Route("captcha")] public bool Captcha([FromBody] string token) { bool isHuman = true; try { string secretKey = ConfigurationManager.AppSettings["reCaptchaPrivateKey"]; Uri uri = new Uri("https://www.google.com/recaptcha/api/siteverify" + $"?secret={secretKey}&response={token}"); HttpWebRequest request = WebRequest.CreateHttp(uri); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = 0; HttpWebResponse response = (HttpWebResponse) request.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream); string result = streamReader.ReadToEnd(); ReCaptchaResponse reCaptchaResponse = JsonConvert.DeserializeObject<ReCaptchaResponse>(result); isHuman = reCaptchaResponse.Success; } catch (Exception ex) { Trace.WriteLine("reCaptcha error: " + ex); } return isHuman; }
I found the answer, I created a hidden input with a certain name and updated its value on Captcha call back. Code: <input type="hidden" value="" id="recaptcha" name="recaptcha" /> <div class="g-recaptcha" data-callback="imNotARobot" data-sitekey="key"></div> and the Javascript is: <script type="text/javascript"> var imNotARobot = function () { $("#recaptcha").val(grecaptcha.getResponse()); }; </script> server side: public string Recaptcha { get; set; } and the model binder does all the work.
I assume this request is coming from a form, change this: var response = Request["g-recaptcha-response"]; To this: var response = Request.Form["g-Recaptcha-Response"]; Also Change this: var result = client.DownloadString($"https://www.google.com/recaptcha/api/siteverify?secret={secretKey}&response={response}"); To this: var result = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secretKey, response));
I need to send notification to mobile by using firebase cloud message my service build in WCF api
I tried to use this code I got from this website. It just returns (successful: False) and I don't know why AndroidFCMPushNotificationStatus Class to return the feed back from the FCM server. Link of the Code I try it. public AndroidFCMPushNotificationStatus SendNotification(string serverApiKey, string senderId, string deviceId, string message) { AndroidFCMPushNotificationStatus result = new AndroidFCMPushNotificationStatus(); try { result.Successful = false; result.Error = null; var value = message; WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send"); tRequest.Method = "post"; tRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8"; tRequest.Headers.Add(string.Format("Authorization: key={0}", serverApiKey)); tRequest.Headers.Add(string.Format("Sender: id={0}", senderId)); string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "®istration_id=" + deviceId + ""; Byte[] byteArray = Encoding.UTF8.GetBytes(postData); tRequest.ContentLength = byteArray.Length; using (Stream dataStream = tRequest.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); using (WebResponse tResponse = tRequest.GetResponse()) { using (Stream dataStreamResponse = tResponse.GetResponseStream()) { using (StreamReader tReader = new StreamReader(dataStreamResponse)) { String sResponseFromServer = tReader.ReadToEnd(); result.Response = sResponseFromServer; } } } } } catch (Exception ex) { result.Successful = false; result.Response = null; result.Error = ex; } return result; } public class AndroidFCMPushNotificationStatus { public bool Successful { get; set; } public string Response { get; set; } public Exception Error { get; set; } }
I find the answer of this problem in other question. The solution is using anonymous types then convert it to Json by JavaScriptSerializer. You can read it in this link.
Send push to Android by C# using FCM (Firebase Cloud Messaging)
I am using this code to send notification message by C# with GCM, using Winforms, Webforms, whatever. Now I want to send to FCM (Firebase Cloud Messaging). Should I update my code? : public class AndroidGCMPushNotification { public AndroidGCMPushNotification() { // // TODO: Add constructor logic here // } public string SendNotification(string deviceId, string message) { string SERVER_API_KEY = "server api key"; var SENDER_ID = "application number"; var value = message; WebRequest tRequest; tRequest = WebRequest.Create("https://android.googleapis.com/gcm/send"); tRequest.Method = "post"; tRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8"; tRequest.Headers.Add(string.Format("Authorization: key={0}", SERVER_API_KEY)); tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID)); string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "®istration_id=" + deviceId + ""; Console.WriteLine(postData); Byte[] byteArray = Encoding.UTF8.GetBytes(postData); tRequest.ContentLength = byteArray.Length; Stream dataStream = tRequest.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); WebResponse tResponse = tRequest.GetResponse(); dataStream = tResponse.GetResponseStream(); StreamReader tReader = new StreamReader(dataStream); String sResponseFromServer = tReader.ReadToEnd(); tReader.Close(); dataStream.Close(); tResponse.Close(); return sResponseFromServer; } } but the GCM was changed to FCM. Is this same code to send the notification? Where can I find the SERVER_API_KEY? Is the same solution?
firebase cloud messaging with c#: working all .net platform (asp.net, .netmvc, .netcore) WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send"); tRequest.Method = "post"; //serverKey - Key from Firebase cloud messaging server tRequest.Headers.Add(string.Format("Authorization: key={0}", "AIXXXXXX....")); //Sender Id - From firebase project setting tRequest.Headers.Add(string.Format("Sender: id={0}", "XXXXX..")); tRequest.ContentType = "application/json"; var payload = new { to = "e8EHtMwqsZY:APA91bFUktufXdsDLdXXXXXX..........XXXXXXXXXXXXXX", priority = "high", content_available = true, notification = new { body = "Test", title = "Test", badge = 1 }, data = new { key1 = "value1", key2 = "value2" } }; string postbody = JsonConvert.SerializeObject(payload).ToString(); Byte[] byteArray = Encoding.UTF8.GetBytes(postbody); tRequest.ContentLength = byteArray.Length; using (Stream dataStream = tRequest.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); using (WebResponse tResponse = tRequest.GetResponse()) { using (Stream dataStreamResponse = tResponse.GetResponseStream()) { if (dataStreamResponse != null) using (StreamReader tReader = new StreamReader(dataStreamResponse)) { String sResponseFromServer = tReader.ReadToEnd(); //result.Response = sResponseFromServer; } } } }
Here is another approach of writing Notification Service inside ASP.Net REST API. public async Task<bool> NotifyAsync(string to, string title, string body) { try { // Get the server key from FCM console var serverKey = string.Format("key={0}", "Your server key - use app config"); // Get the sender id from FCM console var senderId = string.Format("id={0}", "Your sender id - use app config"); var data = new { to, // Recipient device token notification = new { title, body } }; // Using Newtonsoft.Json var jsonBody = JsonConvert.SerializeObject(data); using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/fcm/send")) { httpRequest.Headers.TryAddWithoutValidation("Authorization", serverKey); httpRequest.Headers.TryAddWithoutValidation("Sender", senderId); httpRequest.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); using (var httpClient = new HttpClient()) { var result = await httpClient.SendAsync(httpRequest); if (result.IsSuccessStatusCode) { return true; } else { // Use result.StatusCode to handle failure // Your custom error handler here _logger.LogError($"Error sending notification. Status Code: {result.StatusCode}"); } } } } catch (Exception ex) { _logger.LogError($"Exception thrown in Notify Service: {ex}"); } return false; } References: using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Net.Http; using System.Text; using System.Threading.Tasks;
I have posted this answer as this question was viewed most and this server side code was written in VS 2015 in C# for sending push notification either single device based on device id or subscribed topic to Xamarin Android app public class FCMPushNotification { public FCMPushNotification() { // TODO: Add constructor logic here } public bool Successful { get; set; } public string Response { get; set; } public Exception Error { get; set; } public FCMPushNotification SendNotification(string _title, string _message, string _topic) { FCMPushNotification result = new FCMPushNotification(); try { result.Successful = true; result.Error = null; // var value = message; var requestUri = "https://fcm.googleapis.com/fcm/send"; WebRequest webRequest = WebRequest.Create(requestUri); webRequest.Method = "POST"; webRequest.Headers.Add(string.Format("Authorization: key={0}", YOUR_FCM_SERVER_API_KEY)); webRequest.Headers.Add(string.Format("Sender: id={0}", YOUR_FCM_SENDER_ID)); webRequest.ContentType = "application/json"; var data = new { // to = YOUR_FCM_DEVICE_ID, // Uncoment this if you want to test for single device to="/topics/"+_topic, // this is for topic notification=new { title=_title, body=_message, //icon="myicon" } }; var serializer = new JavaScriptSerializer(); var json = serializer.Serialize(data); Byte[] byteArray = Encoding.UTF8.GetBytes(json); webRequest.ContentLength = byteArray.Length; using (Stream dataStream = webRequest.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); using (WebResponse webResponse = webRequest.GetResponse()) { using (Stream dataStreamResponse = webResponse.GetResponseStream()) { using (StreamReader tReader = new StreamReader(dataStreamResponse)) { String sResponseFromServer = tReader.ReadToEnd(); result.Response = sResponseFromServer; } } } } } catch(Exception ex) { result.Successful = false; result.Response = null; result.Error = ex; } return result; } } and its uses // start sending push notification to apps FCMPushNotification fcmPush = new FCMPushNotification(); fcmPush.SendNotification("your notificatin title", "Your body message","news"); // end push notification
Yes, you should update your code to use Firebase Messaging interface. There's a GitHub Project for that here. using Stimulsoft.Base.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Web; namespace _WEBAPP { public class FireBasePush { private string FireBase_URL = "https://fcm.googleapis.com/fcm/send"; private string key_server; public FireBasePush(String Key_Server) { this.key_server = Key_Server; } public dynamic SendPush(PushMessage message) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(FireBase_URL); request.Method = "POST"; request.Headers.Add("Authorization", "key=" + this.key_server); request.ContentType = "application/json"; string json = JsonConvert.SerializeObject(message); //json = json.Replace("content_available", "content-available"); byte[] byteArray = Encoding.UTF8.GetBytes(json); request.ContentLength = byteArray.Length; Stream dataStream = request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); HttpWebResponse respuesta = (HttpWebResponse)request.GetResponse(); if (respuesta.StatusCode == HttpStatusCode.Accepted || respuesta.StatusCode == HttpStatusCode.OK || respuesta.StatusCode == HttpStatusCode.Created) { StreamReader read = new StreamReader(respuesta.GetResponseStream()); String result = read.ReadToEnd(); read.Close(); respuesta.Close(); dynamic stuff = JsonConvert.DeserializeObject(result); return stuff; } else { throw new Exception("Ocurrio un error al obtener la respuesta del servidor: " + respuesta.StatusCode); } } } public class PushMessage { private string _to; private PushMessageData _notification; private dynamic _data; private dynamic _click_action; public dynamic data { get { return _data; } set { _data = value; } } public string to { get { return _to; } set { _to = value; } } public PushMessageData notification { get { return _notification; } set { _notification = value; } } public dynamic click_action { get { return _click_action; } set { _click_action = value; } } } public class PushMessageData { private string _title; private string _text; private string _sound = "default"; //private dynamic _content_available; private string _click_action; public string sound { get { return _sound; } set { _sound = value; } } public string title { get { return _title; } set { _title = value; } } public string text { get { return _text; } set { _text = value; } } public string click_action { get { return _click_action; } set { _click_action = value; } } } }
Based on Teste's code .. I can confirm the following works. I can't say whether or not this is "good" code, but it certainly works and could get you back up and running quickly if you ended up with GCM to FCM server problems! public AndroidFCMPushNotificationStatus SendNotification(string serverApiKey, string senderId, string deviceId, string message) { AndroidFCMPushNotificationStatus result = new AndroidFCMPushNotificationStatus(); try { result.Successful = false; result.Error = null; var value = message; WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send"); tRequest.Method = "post"; tRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8"; tRequest.Headers.Add(string.Format("Authorization: key={0}", serverApiKey)); tRequest.Headers.Add(string.Format("Sender: id={0}", senderId)); string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "®istration_id=" + deviceId + ""; Byte[] byteArray = Encoding.UTF8.GetBytes(postData); tRequest.ContentLength = byteArray.Length; using (Stream dataStream = tRequest.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); using (WebResponse tResponse = tRequest.GetResponse()) { using (Stream dataStreamResponse = tResponse.GetResponseStream()) { using (StreamReader tReader = new StreamReader(dataStreamResponse)) { String sResponseFromServer = tReader.ReadToEnd(); result.Response = sResponseFromServer; } } } } } catch (Exception ex) { result.Successful = false; result.Response = null; result.Error = ex; } return result; } public class AndroidFCMPushNotificationStatus { public bool Successful { get; set; } public string Response { get; set; } public Exception Error { get; set; } }
You need change url from https://android.googleapis.com/gcm/send to https://fcm.googleapis.com/fcm/send and change your app library too. this tutorial can help you https://firebase.google.com/docs/cloud-messaging/server#implementing-http-connection-server-protocol
Try to send a json object. Replace this: tRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8"; string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "®istration_id=" + deviceId + ""; Console.WriteLine(postData); Byte[] byteArray = Encoding.UTF8.GetBytes(postData); For this: tRequest.ContentType = "application/json"; var data = new { to = deviceId, notification = new { body = "This is the message", title = "This is the title", icon = "myicon" } }; var serializer = new JavaScriptSerializer(); var json = serializer.Serialize(data); Byte[] byteArray = Encoding.UTF8.GetBytes(json);
Here's the code for server side firebase cloud request from C# / Asp.net. Please note that your client side should have same topic. e.g. FirebaseMessaging.getInstance().subscribeToTopic("news"); public String SendNotificationFromFirebaseCloud() { var result = "-1"; var webAddr = "https://fcm.googleapis.com/fcm/send"; var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr); httpWebRequest.ContentType = "application/json"; httpWebRequest.Headers.Add("Authorization:key=" + YOUR_FIREBASE_SERVER_KEY); httpWebRequest.Method = "POST"; using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { string json = "{\"to\": \"/topics/news\",\"data\": {\"message\": \"This is a Firebase Cloud Messaging Topic Message!\",}}"; streamWriter.Write(json); streamWriter.Flush(); } var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } return result; }
You can use this library, makes it seamless to send push notifications using Firebase Service from a C# backend download here
public SendNotice(int deviceType, string deviceToken, string message, int badge, int status, string sound) { AndroidFCMPushNotificationStatus result = new AndroidFCMPushNotificationStatus(); try { result.Successful = false; result.Error = null; var value = message; WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send"); tRequest.Method = "post"; tRequest.ContentType = "application/json"; var serializer = new JavaScriptSerializer(); var json = ""; tRequest.Headers.Add(string.Format("Authorization: key={0}", "AA******")); tRequest.Headers.Add(string.Format("Sender: id={0}", "11********")); if (DeviceType == 2) { var body = new { to = deviceToken, data = new { custom_notification = new { title = "Notification", body = message, sound = "default", priority = "high", show_in_foreground = true, targetScreen = notificationType,//"detail", }, }, priority = 10 }; json = serializer.Serialize(body); } else { var body = new { to = deviceToken, content_available = true, notification = new { title = "Notification", body = message, sound = "default", show_in_foreground = true, }, data = new { targetScreen = notificationType, id = 0, }, priority = 10 }; json = serializer.Serialize(body); } Byte[] byteArray = Encoding.UTF8.GetBytes(json); tRequest.ContentLength = byteArray.Length; using (Stream dataStream = tRequest.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); using (WebResponse tResponse = tRequest.GetResponse()) { using (Stream dataStreamResponse = tResponse.GetResponseStream()) { using (StreamReader tReader = new StreamReader(dataStreamResponse)) { String sResponseFromServer = tReader.ReadToEnd(); result.Response = sResponseFromServer; } } } } } catch (Exception ex) { result.Successful = false; result.Response = null; result.Error = ex; } }
I write this code and It's worked for me . public static string ExcutePushNotification(string title, string msg, string fcmToken, object data) { var serverKey = "AAAA*******************"; var senderId = "3333333333333"; var result = "-1"; var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://fcm.googleapis.com/fcm/send"); httpWebRequest.ContentType = "application/json"; httpWebRequest.Headers.Add(string.Format("Authorization: key={0}", serverKey)); httpWebRequest.Headers.Add(string.Format("Sender: id={0}", senderId)); httpWebRequest.Method = "POST"; var payload = new { notification = new { title = title, body = msg, sound = "default" }, data = new { info = data }, to = fcmToken, priority = "high", content_available = true, }; var serializer = new JavaScriptSerializer(); using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { string json = serializer.Serialize(payload); streamWriter.Write(json); streamWriter.Flush(); } var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } return result; }
I am using this approach and it is working fine: public class PushNotification { private static readonly ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); // firebase private static Uri FireBasePushNotificationsURL = new Uri("https://fcm.googleapis.com/fcm/send"); private static string ServerKey = ConfigurationManager.AppSettings["FIREBASESERVERKEY"]; public static async Task<bool> SendPushNotification(List<SendNotificationModel> notificationData) { try { bool sent = false; foreach (var data in notificationData) { var messageInformation = new Message() { notification = new Notification() { title = data.Title, text = data.Message, ClickAction = "FCM_PLUGIN_ACTIVITY" }, data = data.data, priority="high", to =data.DeviceId }; string jsonMessage = JsonConvert.SerializeObject(messageInformation); //Create request to Firebase API var request = new HttpRequestMessage(HttpMethod.Post, FireBasePushNotificationsURL); request.Headers.TryAddWithoutValidation("Authorization", "key=" + ServerKey); request.Content = new StringContent(jsonMessage, Encoding.UTF8, "application/json"); HttpResponseMessage result; using (var client = new HttpClient()) { result = await client.SendAsync(request); sent = result.IsSuccessStatusCode; } } return sent; } catch(Exception ex) { Logger.Error(ex); return false; } } }
Following Approach, I have used for writing Firebase Notification Service inside ASP.Net REST API. public async Task<bool> NotifyAsync(string to, string title, string body) { try { //Server key from FCM console var serverKey = string.Format("key={0}", "Provide your Server key here from Fibase console"); //Sender id from FCM console var senderId = string.Format("id={0}", "Provide your Sender Id here from Firebase Console"); var data = new { to, // Recipient device token notification = new { title, body } }; // Using Newtonsoft.Json var jsonBody = JsonConvert.SerializeObject(data); using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/fcm/send")) { httpRequest.Headers.TryAddWithoutValidation("Authorization", serverKey); httpRequest.Headers.TryAddWithoutValidation("Sender", senderId); httpRequest.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); using (var httpClient = new HttpClient()) { var result = await httpClient.SendAsync(httpRequest); if (result.IsSuccessStatusCode) { return true; } else { // Use result.StatusCode to handle failure // Your custom error handler here return false; } } } } catch (Exception ex) { throw ex; } return false; } Refer This blog for send Group Notification https://firebase.google.com/docs/cloud-messaging/android/send-multiple
How to send push notification to more then 1000 user through GCM
I'm using asp.net c# to send push notifications to users through GCM. This is my code to send notification. string RegArr = string.Empty; RegArr = string.Join("\",\"", RegistrationID); // (RegistrationID) is Array of endpoints string message = "some test message"; string tickerText = "example test GCM"; string contentTitle = "content title GCM"; postData = "{ \"registration_ids\": [ \"" + RegArr + "\" ], " + "\"data\": {\"tickerText\":\"" + tickerText + "\", " + "\"contentTitle\":\"" + contentTitle + "\", " + "\"message\": \"" + message + "\"}}"; string response = SendGCMNotification("Api key", postData); SendGCMNotification Function:- private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json") { byte[] byteArray = Encoding.UTF8.GetBytes(postData); // CREATE REQUEST HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send"); Request.Method = "POST"; Request.KeepAlive = false; Request.ContentType = postDataContentType; Request.Headers.Add(string.Format("Authorization: key={0}", apiKey)); Request.ContentLength = byteArray.Length; Stream dataStream = Request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); // // SEND MESSAGE try { WebResponse Response = Request.GetResponse(); HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode; if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden)) { var text = "Unauthorized - need new token"; } else if (!ResponseCode.Equals(HttpStatusCode.OK)) { var text = "Response from web service isn't OK"; } StreamReader Reader = new StreamReader(Response.GetResponseStream()); string responseLine = Reader.ReadToEnd(); Reader.Close(); return responseLine; } catch (Exception ex) { throw ex; } return "error"; } It is working properly and notification delivered properly to 1000 users.But now i have more then 1000 users and i have to send notifications to them all,but in gcm documentation it is specified that we can pass 1000 registrations ids at one time.what can i do to send notification to all user?Any help will be appriciated
Well probably you get exception because you are not setting content type. I found article how to send data and rewrote it to your needs. You also would need to install Json.Net package public class NotificationManager { private readonly string AppId; private readonly string SenderId; public NotificationManager(string appId, string senderId) { AppId = appId; SenderId = senderId; // // TODO: Add constructor logic here // } public void SendNotification(List<string> deviceRegIds, string tickerText, string contentTitle, string message) { var skip = 0; const int batchSize = 1000; while (skip < deviceRegIds.Count) { try { var regIds = deviceRegIds.Skip(skip).Take(batchSize); skip += batchSize; WebRequest wRequest; wRequest = WebRequest.Create("https://android.googleapis.com/gcm/send"); wRequest.Method = "POST"; wRequest.ContentType = " application/json;charset=UTF-8"; wRequest.Headers.Add(string.Format("Authorization: key={0}", AppId)); wRequest.Headers.Add(string.Format("Sender: id={0}", SenderId)); var postData = JsonConvert.SerializeObject(new { collapse_key = "score_update", time_to_live = 108, delay_while_idle = true, data = new { tickerText, contentTitle, message }, registration_ids = regIds }); var bytes = Encoding.UTF8.GetBytes(postData); wRequest.ContentLength = bytes.Length; var stream = wRequest.GetRequestStream(); stream.Write(bytes, 0, bytes.Length); stream.Close(); var wResponse = wRequest.GetResponse(); stream = wResponse.GetResponseStream(); var reader = new StreamReader(stream); var response = reader.ReadToEnd(); var httpResponse = (HttpWebResponse) wResponse; var status = httpResponse.StatusCode.ToString(); reader.Close(); stream.Close(); wResponse.Close(); //TODO check status } catch(Exception ex) { Console.WriteLine(ex.Message); } } } Then you can call method var notificationManager = new NotificationManager("AppId", "SenderId"); notificationManager.SendNotification(Enumerable.Repeat("test", 1010).ToList(), "tickerText", "contentTitle", "message");