I am trying to get EWS's push notifications set up in my c# app.
After getting the response from the server and reading it using a NetworkStream I need to respond to the server with Ok in a SOAP message. The only example that I can find uses Microsoft.Web.Services3 and a SoapEnvelope. My understanding is that this has now been replaced by WCF and I really want to use the newer technologies (to learn them).
How would I go by sending a SOAP message back to the server, presumably using the same NetworkStream that I get the notification on?
Here is some code that I tried, but it fails for some reason.
const string RESPONSE_OK = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope\"><soap:Body>" +
"<SendNotificationResult xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" +
"<SubscriptionStatus>OK</SubscriptionStatus></SendNotificationResult></soap:Body></soap:Envelope>";
responseBytes = encoding.GetBytes(RESPONSE_OK);
// Send the result
HTTPResponseStruct _httpResponse;
_httpResponse.version = "HTTP/1.1";
_httpResponse.BodyData = responseBytes;
_httpResponse.Headers = new Hashtable();
_httpResponse.Headers.Add("Server", "IT12");
_httpResponse.Headers.Add("Date", DateTime.Now.ToString("r"));
_httpResponse.Headers.Add("Content-Type", "text/xml; charset=utf-8");
_httpResponse.Headers.Add("Content-Length", _httpResponse.BodyData.Length);
_httpResponse.Headers.Add("Connection", "close");
string HeadersString = _httpResponse.version + " "
+ "200 OK" + "\r\n";
foreach (DictionaryEntry Header in _httpResponse.Headers)
{
HeadersString += Header.Key + ": " + Header.Value + "\r\n";
}
HeadersString += "\r\n";
byte[] bHeadersString = Encoding.ASCII.GetBytes(HeadersString);
// Send headers
clientStream.Write(bHeadersString, 0, bHeadersString.Length);
// Send body
if (_httpResponse.BodyData != null)
clientStream.Write(_httpResponse.BodyData, 0,
_httpResponse.BodyData.Length);
// clientStream.Write(responseBytes, 0, responseBytes.Length);
clientStream.Flush();
Thanks,
Pieter
you can use Microsoft.Exchange.WebServices.Data (EWS Managed API Reference)
http://msdn.microsoft.com/en-us/library/dd633710%28v=EXCHG.80%29.aspx
You marked the other answer as "accepted" but the link you are referring to talks about streaming subscriptions. These are only available for Exchange 2010 and later. For those who are stuck with Exchange Server 2007, there is a Push-Notification library on CodePlex.
Related
So I hava an app which creates a JSON file with some data from the user. This data should be decoded and stored to the database through a PHP script located on my server. I want to post the $_POST variable filename to the php script to use this to retrieve the JSON file. Here is my current PHP script:
<?php
$host='myip';
$user='username';
$pass='userpass';
$db='database';
$link= mysqli_connect($host, $user, $pass, $db) or die(msqli_error($link));
$filename = $_POST['filename'] . '.json';
$json = file_get_contents($filename);
$obj = json_decode($json,true);
foreach ($obj as $data)
{
$query_opslaan = "INSERT INTO skMain (BedrijfsName, ContPers, TelNum, email, Land, Plaats, PostCode) VALUES ('". $data['bedrijfsNaam'] ."' , '". $data['ContPers'] ."', '". $data['TelNum'] ."', '". $data['email'] ."', '". $data['Land'] ."', '". $data['Plaats'] ."', '". $data['PostCode'] ."')";
}
?>
And this is my JSON file
{
"bedrijfsNaam":"JohnDoeMedia",
"ContPers":"John Doe",
"TelNum":"1234567890",
"email":"test#test.nl",
"Land":"Nederland",
"Plaats":"somewhere",
"PostCode":"1234 AB"
}
I currently only have the upload script in C# but I don't know how to use it to run this PHP script and store data to the PHP variable $_POST['filename'] Here is the store script:
WebRequest hwr = WebRequest.Create(serverPath);
hwr.Method = WebRequestMethods.Ftp.UploadFile;
hwr.Credentials = new NetworkCredential(ftpUser, ftpPass);
if (reqCat == "bvg")
{
json = "{\"bedrijfsNaam\":\"" + bedrijfsNaam + "\"," +
"\"ContPers\":\"" + ContPers + "\"," +
"\"TelNum\":\"" + TelNum + "\"," +
"\"email\":\"" + email + "\"," +
"\"Land\":\"" + Land + "\"," +
"\"Plaats\":\"" + Plaats + "\"," +
"\"PostCode\":\"" + PostCode + "\"}";
using (var sw = new StreamWriter(hwr.GetRequestStream()))
{
sw.Write(json);
sw.Flush();
sw.Close();
}
}
Can someone please teach me the method to make this work?
I'm going to take a stab at this because I think you are possibly confused. You mention you are trying to POST the data but your code shows you are trying to FTP directly to the server.
I've included code I've used to FTP to a server. If you actually want to post via a web service call this won't do that.
FtpWebRequest lRequest = (FtpWebRequest)WebRequest.Create(serverPath);
lRequest.Method = WebRequestMethods.Ftp.UploadFile;
lRequest.Credentials = new NetworkCredential(ftpUser, ftpPass);
StreamReader lReader = new StreamReader(json);
//convert steam to utf8
byte[] lContents = Encoding.UTF8.GetBytes(lReader.ReadToEnd());
lReader.Close();
//Get length of data to post
lRequest.ContentLength = lContents.Length;
//Get your request stream
Stream lRequestStream = lRequest.GetRequestStream();
//Write to the stream
lRequestStream.Write(lContents, 0, lContents.Length);
//Close the stream
lRequestStream.Close();
//Get the response from the server
FtpWebResponse lResponse = (FtpWebResponse)lRequest.GetResponse();
//What is the actual status.
MessageBox.Show(String.Format("Upload File Complete, status {0}", lResponse.StatusDescription));
Note you'll have to do the using and whatnot like you are but I have used that code to ftp to a server. I modified it slightly to try and use your variable names though.
Since the request was to use HTTP to send just a filename I've added that to my answer. In the code below the big part is the uri. I am assuming that you can just create your URI to be the web service that runs the php. It would look something like... Where SERVERPATH is your server with the script.php and assuming the parameter your php script is looking for is called FileName. The code also includes handling responses from the server but you might not need to do that depending on what you want the server to do.
Also note that the accept and content type is probably not relevant unless you are expecting a return from the server. The two lines you are mostly concerned with are the WebRequest.Create(xUri) and the lRequest.GetResponse() to actually execute your web request.
http://SERVERPATH/PHP_SCRIPT?FileName=FILENAME
private void CallWebApi(String xUri)
{
String lResults;
using(WebClient lClient = new WebClient()) {
try {
HttpWebRequest lRequest = (HttpWebRequest)WebRequest.Create(xUri);
lRequest.Accept = "application/json";
lRequest.ContentType = "application/json";
HttpWebResponse lResponse = (HttpWebResponse)lRequest.GetResponse();
using(StreamReader lJsonReader = new StreamReader(lResponse.GetResponseStream())) {
lResults = lJsonReader.ReadToEnd();
}
lRequest = (HttpWebRequest)WebRequest.Create(xUri);
lRequest.Accept = "application/xml";
lRequest.ContentType = "application/xml";
lResponse = (HttpWebResponse)lRequest.GetResponse();
using(StreamReader lXMLReader = new StreamReader(lResponse.GetResponseStream())) {
lResults = lXMLReader.ReadToEnd();
}
}
catch(Exception lException) {
MessageBox.Show(lException.Message);
}
}
}
I am working on an android application which uses push notification service by GCM. Currently I am stuck at creating a server. The guides provided by the GCM documentation is in java which I have no idea how to implement. After researching for awhile, I found GCMSharp on github which uses C#
PushSharp - https://github.com/Redth/PushSharp
But as of now, I am new to creating a server and have no idea how to get started. Is the server actually a web service that keeps listening to request and upon getting a request directs it to the GCM which pushes notification to the client phone?
And if yes, do I implement it in a webservice such as WCF?
You could follow this tutorial.
Is the server actually a web service that keeps listening to request
and upon getting a request directs it to the GCM which pushes
notification to the client phone?
You don't need to listen to requests. GCM Push directly pushes any message to the device without any request. For more details, Read this documentation.
I have answered to this on another thread and here i am repeating. Code looks bit longer 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-
I am trying to upload from an HTTP stream directly to S3, without storing in memory or as a file first. I am already doing this with Rackspace Cloud Files as HTTP to HTTP, however the AWS authentication is beyond me so am trying to use the SDK.
The problem is the upload stream is failing with this exception:
"This stream does not support seek operations."
I've tried with PutObject and TransferUtility.Upload, both fail with the same thing.
Is there any way to stream into S3 as the stream comes in, rather than buffering the whole thing to a MemoryStream or FileStream?
or is there any good examples of doing the authentication into S3 request using HTTPWebRequest, so I can duplicate what I do with Cloud Files?
Edit: or is there a helper function in the AWSSDK for generating the authorization header?
CODE:
This is the failing S3 part (both methods included for completeness):
string uri = RSConnection.StorageUrl + "/" + container + "/" + file.SelectSingleNode("name").InnerText;
var req = (HttpWebRequest)WebRequest.Create(uri);
req.Headers.Add("X-Auth-Token", RSConnection.AuthToken);
req.Method = "GET";
using (var resp = req.GetResponse() as HttpWebResponse)
{
using (Stream stream = resp.GetResponseStream())
{
Amazon.S3.Transfer.TransferUtility trans = new Amazon.S3.Transfer.TransferUtility(S3Client);
trans.Upload(stream, config.Element("root").Element("S3BackupBucket").Value, container + file.SelectSingleNode("name").InnerText);
//Use EITHER the above OR the below
PutObjectRequest putReq = new PutObjectRequest();
putReq.WithBucketName(config.Element("root").Element("S3BackupBucket").Value);
putReq.WithKey(container + file.SelectSingleNode("name").InnerText);
putReq.WithInputStream(Amazon.S3.Util.AmazonS3Util.MakeStreamSeekable(stream));
putReq.WithMetaData("content-length", file.SelectSingleNode("bytes").InnerText);
using (S3Response putResp = S3Client.PutObject(putReq))
{
}
}
}
And this is how I do it successfully from S3 to Cloud Files:
using (GetObjectResponse getResponse = S3Client.GetObject(new GetObjectRequest().WithBucketName(bucket.BucketName).WithKey(file.Key)))
{
using (Stream s = getResponse.ResponseStream)
{
//We can stream right from s3 to CF, no need to store in memory or filesystem.
var req = (HttpWebRequest)WebRequest.Create(uri);
req.Headers.Add("X-Auth-Token", RSConnection.AuthToken);
req.Method = "PUT";
req.AllowWriteStreamBuffering = false;
if (req.ContentLength == -1L)
req.SendChunked = true;
using (Stream stream = req.GetRequestStream())
{
byte[] data = new byte[32768];
int bytesRead = 0;
while ((bytesRead = s.Read(data, 0, data.Length)) > 0)
{
stream.Write(data, 0, bytesRead);
}
stream.Flush();
stream.Close();
}
req.GetResponse().Close();
}
}
As no-one answering seems to have done it, I spent the time working it out based on guidance from Steve's answer:
In answer to this question "is there any good examples of doing the authentication into S3 request using HTTPWebRequest, so I can duplicate what I do with Cloud Files?", here is how to generate the auth header manually:
string today = String.Format("{0:ddd,' 'dd' 'MMM' 'yyyy' 'HH':'mm':'ss' 'zz00}", DateTime.Now);
string stringToSign = "PUT\n" +
"\n" +
file.SelectSingleNode("content_type").InnerText + "\n" +
"\n" +
"x-amz-date:" + today + "\n" +
"/" + strBucketName + "/" + strKey;
Encoding ae = new UTF8Encoding();
HMACSHA1 signature = new HMACSHA1(ae.GetBytes(AWSSecret));
string encodedCanonical = Convert.ToBase64String(signature.ComputeHash(ae.GetBytes(stringToSign)));
string authHeader = "AWS " + AWSKey + ":" + encodedCanonical;
string uriS3 = "https://" + strBucketName + ".s3.amazonaws.com/" + strKey;
var reqS3 = (HttpWebRequest)WebRequest.Create(uriS3);
reqS3.Headers.Add("Authorization", authHeader);
reqS3.Headers.Add("x-amz-date", today);
reqS3.ContentType = file.SelectSingleNode("content_type").InnerText;
reqS3.ContentLength = Convert.ToInt32(file.SelectSingleNode("bytes").InnerText);
reqS3.Method = "PUT";
Note the added x-amz-date header as HTTPWebRequest sends the date in a different format to what AWS is expecting.
From there it was just a case of repeating what I was already doing.
Take a look at Amazon S3 Authentication Tool for Curl. From that web page:
Curl is a popular command-line tool for interacting with HTTP
services. This Perl script calculates the proper signature, then calls
Curl with the appropriate arguments.
You could probably adapt it or its output for your use.
I think the problem is that according to the AWS Documentation Content-Length is required and you don't know what the length is until the stream has finished.
(I would guess the Amazon.S3.Util.AmazonS3Util.MakeStreamSeekable routine is reading the whole stream into memory to get around this problem which makes it unsuitable for your scenario.)
What you can do is read the file in chunks and upload them using MultiPart upload.
PS, I assume you know the C# source for the AWSSDK for dotnet is on Github.
This is a true hack (which would probably break with a new implementation of the AWSSDK), and it requires knowledge of the length of the file being requested, but if you wrap the response stream as shown with this class (a gist) as shown below:
long length = fileLength;
you can get file length in several ways. I am uploading from a dropbox link, so they give me the
length along with the url. Alternatively, you can perform a HEAD request and get the Content-Length.
string uri = RSConnection.StorageUrl + "/" + container + "/" + file.SelectSingleNode("name").InnerText;
var req = (HttpWebRequest)WebRequest.Create(uri);
req.Headers.Add("X-Auth-Token", RSConnection.AuthToken);
req.Method = "GET";
using (var resp = req.GetResponse() as HttpWebResponse)
{
using (Stream stream = resp.GetResponseStream())
{
//I haven't tested this path
Amazon.S3.Transfer.TransferUtility trans = new Amazon.S3.Transfer.TransferUtility(S3Client);
trans.Upload(new HttpResponseStream(stream, length), config.Element("root").Element("S3BackupBucket").Value, container + file.SelectSingleNode("name").InnerText);
//Use EITHER the above OR the below
//I have tested this with dropbox data
PutObjectRequest putReq = new PutObjectRequest();
putReq.WithBucketName(config.Element("root").Element("S3BackupBucket").Value);
putReq.WithKey(container + file.SelectSingleNode("name").InnerText);
putReq.WithInputStream(new HttpResponseStream(stream, length)));
//These are necessary for really large files to work
putReq.WithTimeout(System.Threading.Timeout.Infinite);
putReq.WithReadWriteTimeout(System.Thread.Timeout.Infinite);
using (S3Response putResp = S3Client.PutObject(putReq))
{
}
}
}
The hack is overriding the Position and Length properties, and returning 0 for Position{get}, noop'ing Position{set}, and returning the known length for Length.
I recognize that this might not work if you don't have the length or if the server providing the source does not support HEAD requests and Content-Length headers. I also realize it might not work if the reported Content-Length or the supplied length doesn't match the actual length of the file.
In my test, I also supply the Content-Type to the PutObjectRequest, but I don't that that is necessary.
As sgmoore said, the problem is that your content length is not seekable from the HTTP response. However HttpWebResponse does have a content length property available. So you can actually form your Http post request to S3 yourself instead of using the Amazon library.
Here's another Stackoverflow question that managed to do that with what looks like full code to me.
i have to implement push notification in my project.
It has sender(windows phone window application),wcf service and client(windows phone applcation).
How can i replace the sender and use my url to send and recieve notification from client?
i want sender to be some application in emulator itself that run parallely with the client and push data continously to the client.
how to develop such application
can anyone tell the way.
It sounds as though you are looking to use two WP7 apps to send messages back and forth to one another using the push notification functionality. Is that correct?
My understanding it that you will still require a each device to subscribe to a push notification service (MS hosted) using the unique URI sent back when the subscription is successful. It appears that SL3/4 can create HttpWebRequest objects and therefore should be able to formulate a correct package to send, however, the difficulty as I see it will be how to obtain the URI of the device you want to send the post to. Normally the post is sent to the subscriber, which knows its on URI as it was returned during the subscribing phase.
My WCF hosted code only works if the WCF knows the URI of the device, which is sent when the WCF method is called:
public bool sendTileUpdate(string tileText, string url, string image)
{
string TilePushXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Tile>" +
"<wp:BackgroundImage>{2}</wp:BackgroundImage>" +
"<wp:Count>{0}</wp:Count>" +
"<wp:Title>{1}</wp:Title>" +
"</wp:Tile>" +
"</wp:Notification>";
try
{
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(url);
sendNotificationRequest.Method = "POST";
sendNotificationRequest.Headers = new WebHeaderCollection();
sendNotificationRequest.ContentType = "text/xml";
// Tile
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
sendNotificationRequest.Headers.Add("X-NotificationClass", "1");
string str = string.Format(TilePushXML, "", tileText, image);
byte[] strBytes = new UTF8Encoding().GetBytes(str);
sendNotificationRequest.ContentLength = strBytes.Length;
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(strBytes, 0, strBytes.Length);
}
HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
return true;
}
catch (Exception e)
{
return false;
}
}
I know this is a TileNotification, but the principles are the same.
I understand that Mango (WP7.1 & SL4) will support sockets and this might be a more appropriate way for your devices to communicate!
Good luck,
Jason.
im making a Window Application in C# using Socket Programming. I have developed a Server & a Client. Both are working fine but the problem which im gettin is that when ever i send any message from CLIENT, its send perfectly and receives on SERVER but whenever i try to send any message from SERVER it doesn't send to Client, since at the beginning when a connection is built, server sends the message to client that "Connection Established" and received at Client perfectly,but later on server does not send any message to client!!! Could anyone please help me out ???????
Regards
Umair
EDIT:
//Code at SERVER for SENDING...
private void button_send(object sender, EventArgs e)
{
string input = textBoxWrite.Text;
byte[] SendData = new byte[1024];
ASCIIEncoding encoding = new ASCIIEncoding();
SendData = encoding.GetBytes(input);
client.Send(SendData,SendData.Length,SocketFlags.None);
textBoxShow.Text = "Server: " + input;
}
//Code at CLIENT for receiving
NetworkStream networkStream = new NetworkStream(server);
string input = textBoxUser.Text + ": " + textBoxWrite.Text;
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] inputByte = encoding.GetBytes(input);
if (networkStream.CanWrite)
{
networkStream.Write(inputByte, 0, inputByte.Length);
textBoxShow.Text = textBoxShow.Text + Environment.NewLine + input;
textBoxWrite.Text = "";
networkStream.Flush();
}
I'm not sure how best to help based on the information you've provided, but perhaps you could look at something like this example of C# socket programming and compare with your own application.