How-to: Setup Azure Push Notification with Client SDK v3.1.0 and Server SDK v2.0.0 using a CustomAuthController - azure-mobile-services

Since a few days the new Azure Server and Client SDK are available. I had that issue with the App Service Push https://github.com/Azure/azure-mobile-apps-net-server/issues/170#issuecomment-262656329 in last November 2016.
After reading the release blog https://blogs.msdn.microsoft.com/appserviceteam/2017/01/10/azure-mobile-apps-net-sdk-releases/ I can now see that the current
way to register for push notification is deprecated.
Can you please give me detailed instructions what I have to change to use the new App Service Push?
The previous problem was that the
_UserId (SID)
Tag was not properly included in the push notification installation. The _UserId had the MD5 hash of the NameIdentifier instead of the clients unique Id I passed to the CustomAuthController. But I need my clients unique Id afterwards for targeted push notifications to clients utilizing the
_UserId=client-unique-id
Here is my current code in Android:
protected override void OnRegistered(Context context, string registrationId)
{
Log.Verbose("PushHandlerBroadcastReceiver", "GCM Registered: " + registrationId);
App.NotificationHubInstallationId = registrationId;
//await RegisterForPushNotifications(OfflineSyncStoreManager.Instance.MobileAppClient, MainActivity.CurrentActivity);
MainActivity.CurrentActivity.RunOnUiThread(async () =>
{
if (GcmClient.IsRegistered(context))
{
try
{
var pushHub = OfflineSyncStoreManager.Instance.MobileAppClient.GetPush();
const string templateBodyGcm = "{\"data\":{\"message\":\"$(messageParam)\"}}";
var templates = new JObject
{
["genericMessage"] = new JObject
{
{"body", templateBodyGcm}
}
};
//NOTE: Unregister any previous NotificationHub Installation of the TruckerApp on that device
await pushHub.UnregisterAsync().ConfigureAwait(false);
//NOTE_ Register the TruckerApp for Push Notification in the backend.
await pushHub.RegisterAsync(registrationId, templates).ConfigureAwait(false);
MetricsManager.TrackEvent($"PushNotificationHub-{OfflineSyncStoreManager.Instance.MobileAppClient.CurrentUser.UserId}",
new Dictionary<string, string>
{
{"NotificationHubInstallationId", registrationId}
},
new Dictionary<string, double>());
Log.Info("Push Installation Id", App.NotificationHubInstallationId);
}
catch (Exception ex)
{
await MetricsManagerHelper.Instance.SendErrorToApplicationInsightsAsync($"PushNotificationHub Registration failed for reason: {ex.Message}");
DialogNotify("AZURE PUSH Registierungsfehler", "Pushmeldungen sind derzeit nicht verfügbar. " + Environment.NewLine + Environment.NewLine +
"Um neue Aufträge auf Ihr Handy zu übertragen ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine);
}
}
else
{
await MetricsManagerHelper.Instance.SendErrorToApplicationInsightsAsync("GCM/FCM Client is not registered at Google");
DialogNotify("GCM/FCM Push Registrierungsfehler", "Sei konnten nicht beim Google Cloud Messaging angemeldet werden. " +
"Versuchen Sie bitte ein ReLogin oder um neue Aufträge " +
"auf Ihr Handy zu übertragen, ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine);
}
});
}
Here is my current code in iOS:
// We've successfully registered with the Apple notification service, or in our case Azure
public override async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
try
{
const string templateBodyApns = "{\"aps\":{\"alert\":\"$(messageParam)\"}}";
JObject templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBodyApns}
};
// Register for push with your mobile app
Push push = OfflineSyncStoreManager.Instance.MobileAppClient.GetPush();
await push.RegisterAsync(deviceToken, templates);
}
catch (Exception e)
{
UIAlertView avAlert = new UIAlertView("AZURE PUSH Registierungsfehler",
"Pushmeldungen sind derzeit nicht verfügbar. " +
Environment.NewLine +
Environment.NewLine +
"Um neue Aufträge auf Ihr Handy zu übertragen ziehen " +
"Sie bitte in der Truck Auftrag Übericht (hier!) " +
"mit dem Finger von OBEN -> nach -> UNTEN." +
Environment.NewLine +
Environment.NewLine,
null,
"OK",
null);
avAlert.Show();
}
}
Thanks in advance,
Eric

You don't need to unregister and then register - a simple register will do it.
Check out chapter 5 of the book - http://aka.ms/zumobook - there is code within the chapter for each type of push registration that covers the Installation method (where you specify tags and templates together). You can then specify the SID explicitly by constructing a tag that is suitable for your needs.

One save way is to use the Azure Mobile Client installationId, persist it in your backend and use that Id for targeted push notifications to that individual client. Instead sending the push notification to _UserId:your-userid post to $installationId:your-clients-zumo-client-id
But that requires you to store the installationId in your backend SQL Server or other cache (e.g. Redis)
A better solution is to follow both links below:
General App Service Push Notification Installations ZUMO Book
and for custom push notification Tags that Custom Tag Blog

Related

C# Download File from HTTP File Directory getting 401 error or 403 error

I’m trying to download several files from a local network device:
http file directory
I want to write a code that will automatically download all those .avi files to my pc drive.
I have 2 problems:
Problem 1: AUTHENTICATING using WebClient class only.
If I use WebClient class only to connect, I get a 401 Unauthorized error.
Code:
try
{
using (WebClient myWebClient = new WebClient())
{
myWebClient.UseDefaultCredentials = false;
myWebClient.Credentials = new NetworkCredential("user", "pword");
String userName = "user";
String passWord = "pword";
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord));
myWebClient.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials;
Console.WriteLine("Header AUTHORIZATION: "+ myWebClient.Headers[HttpRequestHeader.Authorization].ToString());
// Download the Web resource and save it into the current filesystem folder.
Console.WriteLine("Start DL");
myWebClient.DownloadFile("http://192.168.2.72:81/sd/20170121/record000/P170121_000000_001006.avi", "P170121_000000_001006.avi");
Console.WriteLine("End DL");
}
}
catch(Exception ex)
{
Console.WriteLine("DOWNLOAD ERROR: " + ex.ToString());
}
Error Message: Failure to authenticate
401 Unauthorized Error
Problem 2: Was able to authenticate using WebProxy class but can’t download . Getting 403 Not found error.
Code:
try
{
using (WebClient myWebClient = new WebClient())
{
WebProxy wp = new WebProxy("http://192.168.2.72:81/sd/20170121/record000/",false);
wp.Credentials = new NetworkCredential("user","pword");
Console.WriteLine("Web Proxy: " + wp.Address);
myWebClient.UseDefaultCredentials = false;
myWebClient.Credentials = wp.Credentials;
myWebClient.Proxy = wp;
Console.WriteLine("Downloading File \"{0}\" from \"{1}\"\n\n", filename, wp.Address);
// Download the Web resource and save it into the current filesystem folder.
Console.WriteLine("Start DL");
myWebClient.DownloadFile("http://192.168.2.72:81/sd/20170121/record000/P170121_000000_001006.avi", "P170121_000000_001006.avi");
Console.WriteLine("End DL");
}
}
catch(Exception ex)
{
Console.WriteLine("DOWNLOAD ERROR: " + ex.ToString());
}
Error Message: 403 Not Found
DOWNLOAD ERROR: System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.WebClient.DownloadFile(Uri address, String fileName)
at System.Net.WebClient.DownloadFile(String address, String fileName)
at ConsoleApplication2.Program.Main(String[] args) in C:\Users\Gordon\documents\visual studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 139
Please help me identify if there are any mistakes in my code or is there a better way to submit credentials and download all the files.
Thanks in advance!
I'm not Dot Net developer, I'm just sharing my opinion.
In the second point you have mentioned that you are getting 403 which is the Http status code for Acces Denied. I feel your credentials are not valid or you don't have privilege to do the operation.

Dynamic Storage (S3) access denied

I'm using Amazon's Java client for S3 to access Swisscom's dynamic storage as well as S3 Ninja.
Creating buckets and putting objects works with S3 Ninja (i.e., on localhost). Creating buckets seems to work in the cloud, but putting objects doesn't:
Oct 30 12:04:44 SquaccDevLog 5751ff25-6661-43d6-92ba-91b7c0cf7c55/[App/0]: com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: null)
I may be missing something wrt https://docs.developer.swisscom.com/services/offerings/dynamic.html#authentication - but what (cf. static initializer in the code below)?
Thanks,
Paul
PS: The code below is for the most part (i.e., main and below) Amazon's S3 Java example.
/*
* The MIT License
*
* Copyright (c) 2015 Squeng AG
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package models.s3;
import java.io.*;
import java.util.*;
import play.libs.*;
import com.amazonaws.*;
import com.amazonaws.auth.*;
import com.amazonaws.services.s3.*;
import com.amazonaws.services.s3.model.*;
import com.fasterxml.jackson.databind.node.*;
/**
* Copyright © 2015 Squeng AG
*
* #author Paul
*/
public final class S3Factory
{
private S3Factory()
{
// disable instance construction
}
// FIXME: move to configuration eventually, one for development, testing, and production each
private static final AmazonS3 client;
static {
String vss = System.getenv( "VCAP_SERVICES" );
if ( vss != null ) {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setProtocol( Protocol.HTTPS );
ObjectNode VCAP_SERVICES = (ObjectNode)Json.parse( vss );
ObjectNode dynstrg = (ObjectNode)VCAP_SERVICES.get( "dynstrg" ).get( 0 );
ObjectNode credentials = (ObjectNode)dynstrg.get( "credentials" );
BasicAWSCredentials awsCreds = new BasicAWSCredentials( credentials.get( "accessKey" ).asText(), credentials.get( "sharedSecret" ).asText() );
client = new AmazonS3Client( awsCreds, clientConfig );
client.setEndpoint( credentials.get( "accessHost" ).asText() );
client.setS3ClientOptions( (new S3ClientOptions()).withPathStyleAccess( true ) );
} else {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setProtocol( Protocol.HTTP );
BasicAWSCredentials awsCreds = new BasicAWSCredentials( "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" );
client = new AmazonS3Client( awsCreds, clientConfig );
client.setEndpoint( "localhost:9444/s3" );
client.setS3ClientOptions( (new S3ClientOptions()).withPathStyleAccess( true ) );
}
}
public static AmazonS3 createBucketIfNeedBe( String bucket )
{
if ( !client.doesBucketExist( Objects.requireNonNull( bucket ) ) ) {
// FIXME: barely good enough for only one JVM
synchronized ( bucket.intern() ) {
if ( !client.doesBucketExist( bucket ) ) {
client.createBucket( bucket );
}
}
}
return client;
}
public static void main( String[] args )
throws IOException
{
String bucketName = "my-first-s3-bucket-" + UUID.randomUUID();
String key = "MyObjectKey";
System.out.println( "===========================================" );
System.out.println( "Getting Started with Amazon S3" );
System.out.println( "===========================================\n" );
try {
/*
* Create a new S3 bucket - Amazon S3 bucket names are globally unique, so once a bucket name has been taken by any user, you can't create another bucket with that same name.
*
* You can optionally specify a location for your bucket if you want to keep your data closer to your applications or users.
*/
System.out.println( "Creating bucket " + bucketName + "\n" );
client.createBucket( bucketName );
/*
* List the buckets in your account
*/
// System.out.println( "Listing buckets" );
// for ( Bucket bucket : client.listBuckets() ) {
// System.out.println( " - " + bucket.getName() );
// }
// System.out.println();
/*
* Upload an object to your bucket - You can easily upload a file to S3, or upload directly an InputStream if you know the length of the data in the stream. You can also specify your own metadata when uploading to S3, which allows you set a
* variety of options like content-type and content-encoding, plus additional metadata specific to your applications.
*/
System.out.println( "Uploading a new object to S3 from a file\n" );
client.putObject( new PutObjectRequest( bucketName, key, createSampleFile() ) );
/*
* Download an object - When you download an object, you get all of the object's metadata and a stream from which to read the contents. It's important to read the contents of the stream as quickly as possibly since the data is streamed directly
* from Amazon S3 and your network connection will remain open until you read all the data or close the input stream.
*
* GetObjectRequest also supports several other options, including conditional downloading of objects based on modification times, ETags, and selectively downloading a range of an object.
*/
System.out.println( "Downloading an object" );
S3Object object = client.getObject( new GetObjectRequest( bucketName, key ) );
System.out.println( "Content-Type: " + object.getObjectMetadata().getContentType() );
displayTextInputStream( object.getObjectContent() );
/*
* List objects in your bucket by prefix - There are many options for listing the objects in your bucket. Keep in mind that buckets with many objects might truncate their results when listing their objects, so be sure to check if the returned
* object listing is truncated, and use the AmazonS3.listNextBatchOfObjects(...) operation to retrieve additional results.
*/
// System.out.println( "Listing objects" );
// ObjectListing objectListing = client.listObjects( new ListObjectsRequest().withBucketName( bucketName ).withPrefix( "My" ) );
// for ( S3ObjectSummary objectSummary : objectListing.getObjectSummaries() ) {
// System.out.println( " - " + objectSummary.getKey() + " " + "(size = " + objectSummary.getSize() + ")" );
// }
// System.out.println();
try ( Scanner s = new Scanner( System.in ) ) {
System.out.println( "Unter data/s3 sollten das Bucket und das Object nun ersichtlich sein." );
System.out.println( "Nach dem Drücken der Enter/Return-Taste werden sie wieder gelöscht ..." );
s.nextLine();
}
/*
* Delete an object - Unless versioning has been turned on for your bucket, there is no way to undelete an object, so use caution when deleting objects.
*/
System.out.println( "Deleting an object\n" );
client.deleteObject( bucketName, key );
/*
* Delete a bucket - A bucket must be completely empty before it can be deleted, so remember to delete any objects from your buckets before you try to delete them.
*/
System.out.println( "Deleting bucket " + bucketName + "\n" );
client.deleteBucket( bucketName );
} catch ( AmazonServiceException ase ) {
System.out.println( "Caught an AmazonServiceException, which means your request made it " + "to Amazon S3, but was rejected with an error response for some reason." );
System.out.println( "Error Message: " + ase.getMessage() );
System.out.println( "HTTP Status Code: " + ase.getStatusCode() );
System.out.println( "AWS Error Code: " + ase.getErrorCode() );
System.out.println( "Error Type: " + ase.getErrorType() );
System.out.println( "Request ID: " + ase.getRequestId() );
ase.printStackTrace( System.out );
} catch ( AmazonClientException ace ) {
System.out.println( "Caught an AmazonClientException, which means the client encountered " + "a serious internal problem while trying to communicate with S3, " + "such as not being able to access the network." );
System.out.println( "Error Message: " + ace.getMessage() );
ace.printStackTrace( System.out );
}
}
/**
* Creates a temporary file with text data to demonstrate uploading a file to Amazon S3
*
* #return A newly created temporary file with text data.
*
* #throws IOException
*/
private static File createSampleFile()
throws IOException
{
File file = File.createTempFile( "aws-java-sdk-", ".txt" );
file.deleteOnExit();
Writer writer = new OutputStreamWriter( new FileOutputStream( file ) );
writer.write( "abcdefghijklmnopqrstuvwxyz\n" );
writer.write( "01234567890112345678901234\n" );
writer.write( "!##$%^&*()-=[]{};':',.<>/?\n" );
writer.write( "01234567890112345678901234\n" );
writer.write( "abcdefghijklmnopqrstuvwxyz\n" );
writer.close();
return file;
}
/**
* Displays the contents of the specified input stream as text.
*
* #param input
* The input stream to display as text.
*
* #throws IOException
*/
private static void displayTextInputStream( InputStream input )
throws IOException
{
BufferedReader reader = new BufferedReader( new InputStreamReader( input ) );
while ( true ) {
String line = reader.readLine();
if ( line == null )
break;
System.out.println( " " + line );
}
System.out.println();
}
}
Did you check to put the "PathStyleAccess" for accessing the Swisscom Object Storage ?
Most of the compatible S3 interfaces need this flag on:
This seems to work on my side; here some snippets:
S3ClientOptions options = new S3ClientOptions();
options.setPathStyleAccess(true);
AmazonS3Client client = new AmazonS3Client(new BasicAWSCredentials(uid, secret));
client.setEndpoint("https://ds31s3.swisscom.com");
client.setS3ClientOptions(options);
/*
* Creating a new bucket in the
*/
String newBucket = "mybucket";
client.createBucket(newBucket, "Standard");
/*
* Add a new object
*/
client.putObject(newBucket, "CloudFoundry1.png", objectFile);
client.putObject(newBucket, "CloudFoundry2.png", objectFile);
/*
* List existing objects
*/
ObjectListing objects = client.listObjects("mybucket");
for (S3ObjectSummary summary : objects.getObjectSummaries()) {
System.out.println(summary.getKey()+ " "+summary.getOwner());
}
Hope this helps;
Best
Marco

Paypal-IPN Simulator ends up in HTTP 404 error after successfully completion of the function

have spent lot of hours trying to figure this out with Paypal Simulator, Sandbox but the result is same. My handler function(handleIpn) gets called and processed, with "Verified" "Complete" status but the IPN history as well as the simulator ends up in the HTTP 404 error. On IPN Simulator page the error is - "We're sorry, but there's an HTTP error. Please try again." My set up is Java-Spring MVC.
#RequestMapping(value = "/ipnHandler.html")
public void handleIpn (HttpServletRequest request) throws IpnException {
logger.info("inside ipn");
IpnInfo ipnInfo = new IpnInfo();
Enumeration reqParamNames = request.getParameterNames();
StringBuilder cmd1 = new StringBuilder();
String pName;
String pValue;
cmd1.append("cmd=_notify-validate");
while (reqParamNames.hasMoreElements()) {
pName = (String) reqParamNames.nextElement();
pValue = request.getParameter(pName);
try{
cmd1.append("&").append(pName).append("=").append(pValue);
}
catch(Exception e){
e.printStackTrace();
}
}
try
{
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
HttpsURLConnection con = (HttpsURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "www.sandbox.paypal.com/cgi-bin/webscr");
con.setRequestProperty("Content-length", String.valueOf(cmd1.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(cmd1.toString());
output.flush();
output.close();
//4. Read response from Paypal
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String res = in.readLine();
in.close();
//5. Capture Paypal IPN information
ipnInfo.setLogTime(System.currentTimeMillis());
ipnInfo.setItemName(request.getParameter("item_name"));
ipnInfo.setItemNumber(request.getParameter("item_number"));
ipnInfo.setPaymentStatus(request.getParameter("payment_status"));
ipnInfo.setPaymentAmount(request.getParameter("mc_gross"));
ipnInfo.setPaymentCurrency(request.getParameter("mc_currency"));
ipnInfo.setTxnId(request.getParameter("txn_id"));
ipnInfo.setReceiverEmail(request.getParameter("receiver_email"));
ipnInfo.setPayerEmail(request.getParameter("payer_email"));
ipnInfo.setResponse(res);
// ipnInfo.setRequestParams(reqParamNames);
//6. Validate captured Paypal IPN Information
if (res.equals("VERIFIED")) {
//6.1. Check that paymentStatus=Completed
if(ipnInfo.getPaymentStatus() == null || !ipnInfo.getPaymentStatus().equalsIgnoreCase("COMPLETED"))
ipnInfo.setError("payment_status IS NOT COMPLETED {" + ipnInfo.getPaymentStatus() + "}");
//6.2. Check that txnId has not been previously processed
IpnInfo oldIpnInfo = this.getIpnInfoService().getIpnInfo(ipnInfo.getTxnId());
if(oldIpnInfo != null)
ipnInfo.setError("txn_id is already processed {old ipn_info " + oldIpnInfo);
//6.3. Check that receiverEmail matches with configured {#link IpnConfig#receiverEmail}
if(!ipnInfo.getReceiverEmail().equalsIgnoreCase(this.getIpnConfig().getReceiverEmail()))
ipnInfo.setError("receiver_email " + ipnInfo.getReceiverEmail()
+ " does not match with configured ipn email " + this.getIpnConfig().getReceiverEmail());
//6.4. Check that paymentAmount matches with configured {#link IpnConfig#paymentAmount}
if(Double.parseDouble(ipnInfo.getPaymentAmount()) != Double.parseDouble(this.getIpnConfig().getPaymentAmount()))
ipnInfo.setError("payment amount mc_gross " + ipnInfo.getPaymentAmount()
+ " does not match with configured ipn amount " + this.getIpnConfig().getPaymentAmount());
//6.5. Check that paymentCurrency matches with configured {#link IpnConfig#paymentCurrency}
if(!ipnInfo.getPaymentCurrency().equalsIgnoreCase(this.getIpnConfig().getPaymentCurrency()))
ipnInfo.setError("payment currency mc_currency " + ipnInfo.getPaymentCurrency()
+ " does not match with configured ipn currency " + this.getIpnConfig().getPaymentCurrency());
}
else
ipnInfo.setError("Inavlid response {" + res + "} expecting {VERIFIED}");
logger.info("ipnInfo = " + ipnInfo);
this.getIpnInfoService().log(ipnInfo);
//7. In case of any failed validation checks, throw {#link IpnException}
if(ipnInfo.getError() != null)
throw new IpnException(ipnInfo.getError());
}
catch(Exception e)
{
if(e instanceof IpnException)
throw (IpnException) e;
logger.log(Level.FATAL, e.toString(), e);
throw new IpnException(e.toString());
}
//8. If all is well, return {#link IpnInfo} to the caller for further business logic execution
paymentController.processSuccessfulPayment(ipnInfo);
}
Any help /pointers would greatly appreciate.
thanks.
Finally, got it working! Didn't realize that my issue of redirection in Spring MVC could have impact on Paypal - IPN status. May be my lack of good understanding of HTTP redirections! In above method instead of void return am now returning a jsp page, so "void" is changed to "String" with returning value the jsp file name.
Hope it does help someone!

Windows Azure REST API Update Role Doesn't Take Effect

I'm doing some proof of concept work on azure, trying to get a role using the Get Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roles/<role-name>
And then update the role using the Update Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roleinstances/<role-name>
Both of those URLs are straight from the msdn pages. The GET request works and I get XML that matches what I see in the management console.
When I then add an element to the xml and send that back with a PUT on the update URL, I get a 200 response, but I never see the change in the management console. I also don't see any error message when I send gibberish. I'm connecting from C#, and a coworker suggested I could get the response with this:
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ToString());
But that gets me a 404 error.
Is there an extra step to commit the update? And how can I see the response that msdn mentions?
2 suggestions:
When I am just doing quick SMAPI work I use AzureTools (http://blogs.msdn.com/b/kwill/archive/2013/08/26/azuretools-the-diagnostic-utility-used-by-the-windows-azure-developer-support-team.aspx). Specifically, look in the Misc Tools section under "Service Management REST API". This will show you the full response.
To answer your question about how to get the response (txtSMAPIResponse is where AzureTools puts the response info):
System.IO.Stream receiveStream;
System.IO.StreamReader readStream;
Encoding encode;
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
txtSMAPIRequest.Text = request.Headers.ToString();
txtSMAPIResponse.Text = ex.Message + Environment.NewLine + Environment.NewLine + ex.Response.Headers.ToString();
try
{
receiveStream = ex.Response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
catch
{
}
return;
}
txtSMAPIRequest.Text = request.Method + " " + request.RequestUri + " " + request.ProtocolVersion + Environment.NewLine + Environment.NewLine;
txtSMAPIRequest.Text += request.Headers.ToString();
txtSMAPIResponse.Text = (int)response.StatusCode + " - " + response.StatusDescription + Environment.NewLine + Environment.NewLine;
txtSMAPIResponse.Text += response.Headers + Environment.NewLine + Environment.NewLine;
receiveStream = response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
I've got the same problem. In my case EndPointACL is not getting updated. Very painful thing is for every update , we have to send the entire ConfigurationSet; There is no way to update the ACL for particular end point.
A typical update looks like this:
<?xml version="1.0"?>
<PersistentVMRole xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>100</LocalPort>
<Name>TCP-100</Name>
<Port>100</Port>
<Protocol>tcp</Protocol>
<EndpointACL>
<Rules>
<Rule>
<Order>1</Order>
<Action>deny</Action>
<RemoteSubnet>108.239.229.0/24</RemoteSubnet>
<Description>test-rule</Description>
</Rule>
</Rules>
</EndpointACL>
</InputEndpoint>
</InputEndpoints>
<SubnetNames>
<SubnetName>Subnet-1</SubnetName>
</SubnetNames>
</ConfigurationSet>
</ConfigurationSets>
</PersistentVMRole>

XMPP asmack: Contact presence not working for transitions to "available"

I am using asmack 8-0.8.3.
I don't receive messages for changes of Presence from my contacts when they move to "available".
If one contact passes from "available" to "dnd", I do receive a message. But not in the other way around.
Contact passes: "available" --> "dnd" --> "available" --> "dnd"
I receive: Presence{dnd} Presence{dnd}
Whereas I expect to receive a Presence update {available} between the 2 dnd.
Since I receive presence updates except for "available" I suppose my listener works fine. Also I suppose I correctly subscribed to my contacts' presence...
private class FriendListener implements RosterListener {
public void entriesAdded(Collection<String> addresses) { }
public void entriesUpdated(Collection<String> addresses) { }
public void entriesDeleted(Collection<String> addresses) { }
public void presenceChanged(Presence presence) {
String fromUserID = StringUtils.parseBareAddress(presence.getFrom());
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString() +
" Type=" + presence.getType().toString() +
" Mode=" + presence.getMode().toString()
);
mainCallback_.updatePresenceFriend(fromUserID, presence);
}
}
public void subscribe(String friendID, String friendName) {
Presence presence = new Presence(Presence.Type.subscribe);
connection.sendPacket(presence);
RosterPacket rosterPacket = new RosterPacket();
rosterPacket.setType(IQ.Type.SET);
Item item = new Item(friendID, friendName);
item.setItemType(RosterPacket.ItemType.both);
rosterPacket.addRosterItem(item);
connection.sendPacket(rosterPacket);
System.out.println("Send subscribe to " + friendID);
subscribedUsers.add(friendID);
}
I found the problem!
Actually there was a bug in the log of my Listener, this line:
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString() +
" Type=" + presence.getType().toString() +
" Mode=" + presence.getMode().toString()
);
It made crashed when Presence.getMode()==null, so that I did not process the Presence message. But no coredump was showing in the logs, I guess because the listener is in another thread...
Changing the log by the following line solved the problem
System.out.println(
"Presence changed: " + fromUserID +
" Presence=" + presence.toString()
);