I'm using the following code to send a push raw notification to my app. The code is taken from the examples given in the official documentation.
public string PostToWns(string secret, string sid, string uri, string xml, string notificationType, string contentType)
{
try
{
var accessToken = GetAccessToken(secret, sid);
byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.Headers.Add("X-WNS-Type", notificationType);
request.ContentType = contentType;
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(contentInBytes, 0, contentInBytes.Length);
using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
// ^^^^^ This throws an exception ^^^^^
return webResponse.StatusCode.ToString();
}
catch (WebException webException)
{
HttpStatusCode status = ((HttpWebResponse)webException.Response).StatusCode;
if (status == HttpStatusCode.Unauthorized)
{
GetAccessToken(secret, sid);
return PostToWns(uri, xml, secret, sid, notificationType, contentType);
}
else if (status == HttpStatusCode.Gone || status == HttpStatusCode.NotFound)
{
return "";
}
else if (status == HttpStatusCode.NotAcceptable)
{
return "";
}
else
{
string[] debugOutput = {
status.ToString(),
webException.Response.Headers["X-WNS-Debug-Trace"],
webException.Response.Headers["X-WNS-Error-Description"],
webException.Response.Headers["X-WNS-Msg-ID"],
webException.Response.Headers["X-WNS-Status"]
};
return string.Join(" | ", debugOutput);
}
}
catch (Exception ex)
{
return "EXCEPTION: " + ex.Message;
}
}
// Authorization
[DataContract]
public class OAuthToken
{
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "token_type")]
public string TokenType { get; set; }
}
private OAuthToken GetOAuthTokenFromJson(string jsonString)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
{
var ser = new DataContractJsonSerializer(typeof(OAuthToken));
var oAuthToken = (OAuthToken)ser.ReadObject(ms);
return oAuthToken;
}
}
protected OAuthToken GetAccessToken(string secret, string sid)
{
var urlEncodedSecret = HttpUtility.UrlEncode(secret);
var urlEncodedSid = HttpUtility.UrlEncode(sid);
var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com",
urlEncodedSid,
urlEncodedSecret);
string response;
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = client.UploadString("https://login.live.com/accesstoken.srf", body);
}
return GetOAuthTokenFromJson(response);
}
The server always returns Unauthorized. However, I am able to obtain a token without problems and the channel URL used is obtained as in the official example.
The entire code executes at once, so I doubt the token expires every time.
I tried using online tools to check if push notifications are working and the same Unauthorized error happens there.
Do I have to register for WNS somewhere? My app is already in the Store and I have the ID and password from the Live Services website. I use these as credentials to get the token and the token is obtained every time. I described this as part of a related question: Proper WNS credentials.
Does anyone have any ideas or solutions?
I found an answer in a different question: Windows Notifications Service: 401 Invalid Token when trying to create a Toast notification in PHP.
The client_id must be the full SID (including the protocol prefix) and the client_secret the password.
Related
I'm getting a 500 internal server error when trying to access cherwell REST api via Code trying to return a token to make other calls. I've verified that all the information (username, password, ClientID, and client secret) are all correct. I've also verified the server is up and accepting requests. Something must be wrong with my code. Any help would be great!
string token = "";
string responseBody;
string serverName = "ql1cwbeta1";
//initialize web client
using (WebClient webClient = new WebClient())
{
// pull down parameters for body
string grantType = ConfigurationManager.AppSettings["grant_type"];
string clientId = ConfigurationManager.AppSettings["client_id"];
string username = ConfigurationManager.AppSettings["username"];
string password = ConfigurationManager.AppSettings["password"];
string authMode = ConfigurationManager.AppSettings["auth_mode"];
//add parameters in headers
webClient.Headers.Add("Accept", "application/json");
// adding parameters in body
NameValueCollection values = new NameValueCollection
{
{"grant_type", grantType},
{"client_id", clientId},
{"username", username},
{"password", password},
{"auth_mode", authMode}
};
try
{
byte[] responseBytes = webClient.
UploadValues("http://" + serverName + "/CherwellAPI/token?auth_mode=" + authMode + "&api_key=" + clientId, "POST", values);
responseBody = Encoding.UTF8.GetString(responseBytes);
}
catch (Exception exception)
{
return exception;
}
Hope below code may help you.
public static string TokenRequest()
{
try
{
// Create HTTP Web Request for the token request
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(Values.TokenURL);
byte[] data = Encoding.ASCII.GetBytes("username=" + Username + "&password=" + Password + "&client_id=" + ClientId + "&grant_type=" + GrantType);
// Set request verb POST, content type and content length (length of data)
tokenRequest.Method = "POST";
tokenRequest.ContentType = "application/x-www-form-urlencoded";
tokenRequest.ContentLength = data.Length;
// Stream request data
using (Stream stream = tokenRequest.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
// Get the response and read stream to string
using (WebResponse response = tokenRequest.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
using (StreamReader sr = new StreamReader(stream))
{
// responseText = sr.ReadToEnd();
return sr.ReadToEnd();
}
}
}
}
catch (WebException ex)
{
// Catch error for bad URL (404) or bad request (400) resulting from bad input (username, password, client id, grant type in token request)
if (ex.Message.Contains("400"))
{
// do something for bad request
}
else if (ex.Message.Contains("404"))
{
// do something for not found
}
else
{
// unknown error, do something
}
return null;
}
catch (Exception ex)
{
// General Exception
return null;
}
}
For future reference - You can include the client ID as part of the querystring if all parameters are included in the querystring, but if you are also sending a payload, then authmode should be the only thing in the querystring.
It will accept all of these parameters as querystrings.
However, you should know that for Cherwell specifically, if you are using LDAP auth / user accounts, you may need to URL encode your username values.
There are certain special characters that will break the auth command. Specifically, including a backslash for a domain can cause issues if it's not escaped with %5C , which I believe can cause a 400 error.
Also a cause of an error can be if you've chosen an authmode that's not enabled for the browser apps in the Security Settings page of the admin console ;)
I'm trying to send a push notification from a small code write in c#, here is the code:
public void Launch()
{
string channelUri = "channel uri";
string sid = "sid package";
string secret = "client secret";
// toast notification
var toast = #"<toast><visual><binding template=""ToastText01""><text id=""1"">Hello!</text></binding></visual></toast>";
Console.WriteLine(this.PostToWns(secret, sid, channelUri, toast));
Console.ReadLine();
}
// Post to WNS
public string PostToWns(string secret, string sid, string uri, string xml, string type = "wns/toast")
{
try
{
// You should cache this access token
var accessToken = GetAccessToken(secret, sid);
byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.Headers.Add("X-WNS-Type", type);
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(contentInBytes, 0, contentInBytes.Length);
using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
return webResponse.StatusCode.ToString();
}
catch (WebException webException)
{
string exceptionDetails = webException.Response.Headers["WWW-Authenticate"] ?? string.Empty;
if (exceptionDetails.Contains("Token expired"))
{
GetAccessToken(secret, sid);
// Implement a maximum retry policy
return PostToWns(uri, xml, secret, sid, type);
}
else
{
// Log the response
return "EXCEPTION: " + webException.Message;
}
}
catch (Exception ex)
{
return "EXCEPTION: " + ex.Message;
}
}
// Authorization
[DataContract]
public class OAuthToken
{
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "token_type")]
public string TokenType { get; set; }
}
private OAuthToken GetOAuthTokenFromJson(string jsonString)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
{
var ser = new DataContractJsonSerializer(typeof(OAuthToken));
var oAuthToken = (OAuthToken)ser.ReadObject(ms);
return oAuthToken;
}
}
protected OAuthToken GetAccessToken(string secret, string sid)
{
var urlEncodedSecret = HttpUtility.UrlEncode(secret);
var urlEncodedSid = HttpUtility.UrlEncode(sid);
var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com",
urlEncodedSid,
urlEncodedSecret);
string response;
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = client.UploadString("https://login.live.com/accesstoken.srf", body);
}
return GetOAuthTokenFromJson(response);
}
Where channelUri, sid and secret are fixed variables that I obtained earlier. The problem is that the remote server return the 400 error (Bad Request) but i dont't know why. The channel creation is successful, i followed this guide: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868221.aspx and sid and secret variables refer to the app previously created in the microsoft developer dashboard.
Someone can help me?
HTTP 400 error indicates Bad Request, it means the request could not be understood by the server due to malformed syntax. In the other word, the request sent by the client doesn't follow server's rules.
There are four required headers that must be included in all push notifications: X-WNS-Type, Content-Type, Content-Length, and Authorization.
While using HttpWebResponse, it should be able to set Content-Length for you automatically, but you still need to set the Content-Type manually. And for toast, tile, and badge notifications, this header must be set to "text/xml". For more info, please see Send notification request.
HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.Headers.Add("X-WNS-Type", type);
request.ContentType = "text/xml";
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));
I have followed these two guides:
https://msdn.microsoft.com/en-us/library/windows/apps/hh202945(v=vs.105).aspx
https://msdn.microsoft.com/library/windows/apps/xaml/hh868252
The resulting code is the following. Despite it all seems right, it returns a 404 error. How can this be? Any help will delay my suicide.
public static void PushToWindows2()
{
try
{
var accessToken = GetAccessToken("Nhz******************XkwX", "ms-app://s-1-15-2-***************-2150981501");
byte[] contentInBytes = Encoding.UTF8.GetBytes("<toast launch=\"\"><visual lang=\"en-US\"><binding template=\"ToastImageAndText01\"><image id=\"1\" src=\"World\" /><text id=\"1\">Hello</text></binding></visual></toast>");
HttpWebRequest request = HttpWebRequest.Create("https://db5.notify.windows.com/?token=awyaaaborhlhub%2bfxeytzjnz****************pftroh5l18sgorvgrkq%3d") as HttpWebRequest;
request.Method = "POST";
request.ContentLength = contentInBytes.Length;
request.ContentType= "text/xml";
request.Headers.Add("X-WindowsPhone-Target", "token");
request.Headers.Add("X-NotificationClass", "1"); ;
request.Headers.Add("X-WNS-Type", "wns/toast");
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken.ToString()));
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(contentInBytes, 0, contentInBytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
}
catch (Exception ex)
{
Console.Write("EXCEPTION: " + ex.Message);
}
}
[DataContract]
public class OAuthToken
{
[DataMember(Name = "access_token")]
public string AccessToken { get; set; }
[DataMember(Name = "token_type")]
public string TokenType { get; set; }
}
public static OAuthToken GetOAuthTokenFromJson(string jsonString)
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
{
var ser = new DataContractJsonSerializer(typeof(OAuthToken));
var oAuthToken = (OAuthToken)ser.ReadObject(ms);
return oAuthToken;
}
}
public static OAuthToken GetAccessToken(string secret, string sid)
{
var urlEncodedSecret = HttpUtility.UrlEncode(secret);
var urlEncodedSid = HttpUtility.UrlEncode(sid);
var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com",
urlEncodedSid,
urlEncodedSecret);
string response;
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
response = client.UploadString("https://login.live.com/accesstoken.srf", body);
}
return GetOAuthTokenFromJson(response);
}
I have also tried to go the PushSharp route, in which case, I get the "Device subscription has expired" error. Here goes:
var config = new WnsConfiguration("424****.*******nts", "ms-app://s-1-15-2-***************1501", "Nhz************XkwX");
// Create a new broker
var wnsBroker = new WnsServiceBroker (config);
wnsBroker.QueueNotification(new WnsToastNotification {
ChannelUri = deviceId,
Payload = XElement.Parse (#"
<toast>
<visual>
<binding template=""ToastText01"">
<text id=""1"">WNS_Send_Single</text>
</binding>
</visual>
</toast>")
});
}
Update:
It is not encoding related either. I've used both the unencoded token with = and + signs and the encoding one. Still 404
HTTP 404 error for WNS means that the channel URI itself has been munged with so WNS can't understand it. It looks like from your code the channel URI is getting tolower()ed somewhere - usually the tokens start with something like "AwYAAAD". Try removing whatever's lowercasing the channel URI.
Also, it looks like you're mixing WNS and MSDN documentation when you want WNS (although this is not causing your 404 errors). This is WNS, but this is MPNS documentation. Specifically, these headers are for MPNS and will be ignored or failed by WNS:
X-WindowsPhone-Target
X-NotificationClass
X-NotificationStatus
X-SubscriptionStatus
X-DeviceConnectionStatus
You want to use these WNS headers instead.
I'm trying to access JIRA data (get project) using JIRA REST API. Here is how I'm making it:
public enum JiraResource
{
project
}
public class JiraService : IJiraService
{
#region JiraService member functions
/* public void DoWork()
{
}*/
private const string str_baseURL = "https://jira.atlassian.com/rest/api/latest/issue/JRA-9";
private string str_Username;
private string str_Password;
public JiraService(string username,string password)
{
str_Username = username;
str_Password = password;
}
public string runQuery(
JiraResource resource,
string argument = null,
string data = null,
string method = "GET")
{
string url = string.Format("{0}{1}/",str_baseURL,resource.ToString());
// string url = string.Format("{0}{1}/", str_baseURL);
if(argument != null)
{
url = string.Format("{0}{1}/",url,argument);
}
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = method;
if (data != null)
{
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(data);
}
}
string base64Credentials = GetEncodedCredentials();
request.Headers.Add("Authorization", "Basic " + base64Credentials);
HttpWebResponse response = request.GetResponse() as HttpWebResponse; //Getting error here.
string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{ result = reader.ReadToEnd(); }
return result;
}
private string GetEncodedCredentials()
{
string mergedCredentials = string.Format("{0}:{1}", str_Username, str_Password);
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
I'm using username and password as admin and admin (I think this is default). Please note that, this url ("https://jira.atlassian.com/rest/api/latest/issue/JRA-9") showing me json objects from the browser. However, from my code, I'm getting exception "Remote server returned error (407) proxy authentication required ".
As per this post(The remote server returned an error: (407) Proxy Authentication Required) I used useDefaultCredentials="true". But this is not working.
Is there anything that I'm missing? Please guide me.
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;
}
}
}
}