Cnam azure 2014   mobile services
Upcoming SlideShare
Loading in...5
×
 

Cnam azure 2014 mobile services

on

  • 1,814 views

Support de cours sur Azure au Cnam d'Aymeric Weinbach

Support de cours sur Azure au Cnam d'Aymeric Weinbach
mobile services

Statistics

Views

Total Views
1,814
Views on SlideShare
732
Embed Views
1,082

Actions

Likes
0
Downloads
22
Comments
0

4 Embeds 1,082

http://www.zecloud.fr 1073
http://feedly.com 5
http://www.zecloudstore.com 2
http://zecloudv3.cloudapp.net 2

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Cnam azure 2014   mobile services Cnam azure 2014 mobile services Presentation Transcript

  • Cnam Azure ZeCloud 17/01/2014
  • Windows Azure Mobile Services
  • Multi-Platform Apps
  • You don’t need a different Mobile Service for each platform!
  • Connect them all!
  • Cross-Platform Support
  • Cross-Platform Support
  • Multi-Device Push
  • Windows Store Single Platform Push Notifications push.wns.sendToastText04(item.channel, {text1: text}, … ); Windows Phone push.mpns.sendFlipTile(item.channel, {title: text}, …); iOS push.apns.send(item.token, { alert: text, payload: inAppMessage: Details }}, …); Android push.gcm.send(item.registrationId, item.text, …); {
  • Multi-Platform Push Notifications function sendNotifications() { var deviceInfoTable = tables.getTable('DeviceInfo'); deviceInfoTable.where({ userId : user.userId }).read({ success: function(deviceInfos){ deviceInfos.forEach(function(deviceInfo){ if (deviceInfo.uuid != request.parameters.uuid) { if (deviceInfo.pushToken != null && deviceInfo.pushToken != 'SimulatorToken') { if (deviceInfo.platform == 'iOS') { push.apns.send(deviceInfo.pushToken, { alert: "New something created" } , { //success / error block}); } else if (deviceInfo.platform == 'Android') { push.gcm.send(deviceInfo.pushToken, "New something created", { success / error block}); } } } }); } }); }
  • Don’t forget to check the response on error (or getFeedback for APNS) Also, check out Delivering Push Notifications to Millions of Devices – Friday @12pm
  • Virtual Tables
  • Create a table Use it’s endpoint Don’t call request.Execute
  • Custom API
  • • • • • • • • •
  • Custom API Demo
  • Talking to Azure Storage
  • It’s doable It’s not perfect Scripts and the Azure module
  • Reading Tables var azure = require('azure'); function read(query, user, request) { var accountName = 'accountname'; var accountKey = 'Accountkey------------nKHDsW2/0Jzg=='; var host = accountName + '.table.core.windows.net'; var tableService = azure.createTableService(accountName, accountKey, host); tableService.queryTables(function (error, tables) { if (error) { request.respond(500, error); } else { request.respond(200, tables); } }); }
  • var azure = require('azure'); Reading Table Rows function read(query, user, request) { var accountName = 'accountname'; var accountKey = 'Accountkey------------nKHDsW2/0Jzg=='; var host = accountName + '.table.core.windows.net'; var tableService = azure.createTableService(accountName, accountKey, host); var tq = azure.TableQuery .select() .from(request.parameters.table); tableService.queryEntities(tq, function (error, rows) { if (error) { request.respond(500, error); } else { request.respond(200, rows) } }); }
  • var azure = require('azure'); function insert(item, user, request) { Creating Containers var accountName = 'accountname'; var accountKey = 'Accountkey------------nKHDsW2/0Jzg=='; var host = accountName + '.blob.core.windows.net'; var blobService = azure.createBlobService(accountName, accountKey, host); if (request.parameters.isPublic == 1) { blobService.createContainerIfNotExists(item.containerName ,{publicAccessLevel : 'blob'} , function (error) { if (!error) { request.respond(200, item); } else { /* error */ request.respond(500);} }); } else { blobService.createContainerIfNotExists(item.containerName, function (error) { if (!error) { request.respond(200, item); } else { /*error */ request.respond(500); } }); } }
  • Reading and “Creating” Blobs var azure = require('azure'), qs = require('querystring'); function insert(item, user, request) { var accountName = 'accountname'; var accountKey = 'Accountkey------------nKHDsW2/0Jzg=='; var host = accountName + '.blob.core.windows.net'; var blobService = azure.createBlobService(accountName, accountKey, host); var sharedAccessPolicy = { AccessPolicy: { Permissions: 'rw', //Read and Write permissions Expiry: minutesFromNow(5) } }; var sasUrl = blobService.generateSharedAccessSignature(request.parameters.containerName, request.parameters.blobName, sharedAccessPolicy); var sasQueryString = { 'sasUrl' : sasUrl.baseUrl + sasUrl.path + '?' + qs.stringify(sasUrl.queryString) }; request.respond(200, sasQueryString); } function minutesFromNow(minutes) { var date = new Date() date.setMinutes(date.getMinutes() + minutes); return date; }
  • Storage Demo
  • Talking REST
  • http://Mobileservice.azure-mobile.net/tables/* Action HTTP Verb URL Suffix Create POST /TodoItem Retrieve GET /TodoItem?$filter=id%3D42 Update PATCH /TodoItem/id Delete DELETE /TodoItem/id
  • JSON Value T-SQL Type Numeric values (integer, decimal, floating point) Float Boolean Bit DateTime DateTimeOffset(3) String Nvarchar(max)
  • Postman & Runscope Demo
  • Sending Emails
  • //var crypto = require('crypto'); //item.tempId = new Buffer(crypto.randomBytes(16)).toString('hex'); Sending an Email function sendEmail(item) { var sendgrid = new SendGrid('myaccount@azure.com', 'mypassword'); var email = { to : item.email, from : 'from-me@chrisrisner.com', subject : 'Welcome to MyApp', text: 'Thanks for installing My App! Click this link to verify:nn' + 'http://myapp.azurewebsites.net/activate.html?id=' + item.id + '&tid=' + item.tempId, createDate : new Date() }; sendgrid.send({ to: item.email, from: email.from, subject: email.subject, text: email.text }, function(success, message) { // If the email failed to send, log it as an error so we can investigate if (!success) { console.error(message); } else { saveSentEmail(email); } }); }
  • Setting up SendGrid Demo
  • The CLI
  • SOME It’s awe
  • CLI Demo
  • Service Filters and DelegatingHandlers
  • Client side Intercepts requests Intercepts responses
  • Sending Version Info with Each Request - (void)handleRequest:(NSURLRequest *)request next:(MSFilterNextBlock)next response:(MSFilterResponseBlock)response { MSFilterResponseBlock wrappedResponse = ^(NSHTTPURLResponse *innerResponse, NSData *data, NSError *error) { response(innerResponse, data, error); }; // add additional versioning information to the querystring for versioning purposes NSString *append = [NSString stringWithFormat:@"build=%@&version=%@", self.build, self.version]; NSURL *url = nil; NSRange range = [request.URL.absoluteString rangeOfString:@"?"]; if (range.length > 0) { url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&%@&p=iOS", request.URL.absoluteString, append]]; } else { url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@&p=iOS", request.URL.absoluteString, append]]; } NSMutableURLRequest *newRequest = [request mutableCopy]; newRequest.URL = url; next(newRequest, wrappedResponse); }
  • DelegatingHandlers are Service Filters public static MobileServiceClient MobileService = new MobileServiceClient( "https://<your subdomain>.azure-mobile.net/", "<your app key>", new VersionHandler() ); using System; using System.Net.Http; using System.Threading.Tasks; namespace WindowsStore { public class VersionHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.ToString() + "?version=v2"); return base.SendAsync(request, cancellationToken); } } }
  • Script Versioning
  • Checking the Version in Scripts function insert(item, user, request) { if (request.parameters.build < 2.0) { item.description = 'Not entered'; } request.execute({ success : function() { if (request.parameters.build < 2.0) { delete item.description; } request.respond(); } }); }
  • For more on versioning, check out Going Live and Beyond with Windows Azure Mobile Services Friday @ 10:30 am
  • Talking Twitter
  • v1 is dead v1.1 is hard
  • function generateOAuthSignature(method, url, data){ var index = url.indexOf('?'); if (index > 0) url = url.substring(0, url.indexOf('?')); var signingToken = encodeURIComponent('Your Consumer Secret') + "&" + encodeURIComponent('Your Access Token Secret'); var keys = []; for (var d in data){ if (d != 'oauth_signature') { console.log('data: ' , d); keys.push(d); } } keys.sort(); var output = "GET&" + encodeURIComponent(url) + "&"; var params = ""; keys.forEach(function(k){ params += "&" + encodeURIComponent(k) + "=" + encodeURIComponent(data[k]); }); params = encodeURIComponent(params.substring(1)); return hashString(signingToken, output+params, "base64"); } function hashString(key, str, encoding){ var hmac = crypto.createHmac("sha1", key); hmac.update(str); return hmac.digest(encoding); } function generateNonce() { var code = ""; for (var i = 0; i < 20; i++) { code += Math.floor(Math.random() * 9).toString(); } return code; } Part 1: The Helpers
  • var crypto = require('crypto'); var querystring = require('querystring'); function read(query, user, request) { var result = { id: query.id, identities: user.getIdentities(), userName: '' }; var identities = user.getIdentities(); var userId = user.userId; var twitterId = userId.substring(userId.indexOf(':') + 1); //API 1.0 //url = 'https://api.twitter.com/1/users/show/' + twitterId + '.json'; //API 1.1 var url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId; var key = 'This is your consumer key'; var nonce = generateNonce(); var sigmethod = 'HMAC-SHA1'; var version = '1.0'; var twitterAccessToken = identities.twitter.accessToken; var oauth_token = 'The Access Token'; var seconds = new Date() / 1000; seconds = Math.round(seconds); var requestType = 'GET'; var oauthData = { oauth_consumer_key: key, oauth_nonce: nonce, oauth_signature:null, oauth_signature_method: sigmethod, oauth_timestamp: seconds, oauth_token: oauth_token, oauth_version: version }; var sigData = {}; for (var k in oauthData){ sigData[k] = oauthData[k]; } sigData['user_id'] = twitterId; Part 2: The Work (part 1)
  • var sig = generateOAuthSignature('GET', url, sigData); oauthData.oauth_signature = sig; var oauthHeader = ""; for (k in oauthData){ oauthHeader += ", " + encodeURIComponent(k) + "="" + encodeURIComponent(oauthData[k]) + """; } oauthHeader = oauthHeader.substring(1); var authHeader = 'OAuth' + oauthHeader; //Generate callback for response from Twitter API var requestCallback = function (err, resp, body) { if (err || resp.statusCode !== 200) { console.error('Error sending data to the provider: ', err); request.respond(statusCodes.INTERNAL_SERVER_ERROR, body); } else { try { var userData = JSON.parse(body); if (userData.name != null) result.UserName = userData.name; else result.UserName = "can't get username"; request.respond(200, [result]); } catch (ex) { console.error('Error parsing response from the provider API: ', ex); request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex); } } } //Create the request and execute it var req = require('request'); var reqOptions = { uri: url, headers: { Accept: "application/json" } }; if (authHeader != null) reqOptions.headers['Authorization'] = authHeader; req(reqOptions, requestCallback); } Part 2.2: The Work
  • That was terrible Do this
  • The Easy Way exports.post = function(request, response) { var twitter = require(‘ctwitter.js’); twitter.init(’consumer key',’consumer secret'); twitter.tweet(request.body.tweettext, request.user, request); } Get the script here: http://bit.ly/14b73Gg
  • Script Source Control
  • Enable on dashboard Creates Git repo Changes push from client
  • Shared Scripts
  • require(‘jsfile.js'); *Need a config change on update (for now)
  • Auth Part 1: Custom
  • Pass creds in Validate Hash your salt Create a JWT
  • Part 1: The Helpers
  • Part 2: The Work
  • Part 3: Signing In
  • …or just use Auth0 http://aka.ms/authZeroZumo Check out Who’s that User? – Friday @ 2pm
  • Auth Part 2: Identity Caching
  • Storing Credentials in .NET
  • Getting and Setting Credentials
  • Auth Part 3: Expired Tokens
  • Expiration Flow
  • DelegationHandlers (again)
  • ServiceFilter (iOS)
  • Auth Demo
  • One-to-Many
  • Client Server
  • Client
  • Server 1
  • Server 2
  • Remember API call #s when considering client side one-to-many
  • Paging Data
  • Client Server
  • Client
  • Server Scripts
  • On-Prem
  • On-Prem Solutions in Windows Azure Data Synchronization SQL Data Sync Application-Layer Connectivity & Messaging Service Bus Secure Point-to-Site Network Connectivity Windows Azure Virtual Network Secure Site-to-Site Network Connectivity Windows Azure Virtual Network
  • Windows Azure Point-to-Site VPNs <subnet 1> <subnet 2> <subnet 3> DNS Server On-premises VPN Gateway Route-based VPN Your datacenter Individual computers behind corporate firewall Virtual Network
  • Site-to-Site Connectivity • • On-ramp for migrating services to the cloud • Windows Azure Extend your premises to the cloud securely Use your on-prem resources in Azure (monitoring, AD, …) On-premises <subnet 2> <subnet 3> DNS Server VPN Gateway Hardware VPN or Windows RRAS Your datacenter <subnet 1> Virtual Network